diff --git a/build.gradle b/build.gradle index 9bf8d601..ce939f61 100644 --- a/build.gradle +++ b/build.gradle @@ -42,6 +42,9 @@ repositories { dependencies { compile 'org.slf4j:slf4j-api' + compile 'commons-collections:commons-collections' + compile 'org.apache.commons:commons-lang3' + compile 'com.google.guava:guava' testCompile 'junit:junit' testCompile 'ch.qos.logback:logback-classic' } @@ -51,6 +54,9 @@ dependencyManagement { dependency "org.slf4j:slf4j-api:1.7.12" dependency "junit:junit:4.11" dependency "ch.qos.logback:logback-classic:1.1.2" + dependency "commons-collections:commons-collections:3.2.1" + dependency "org.apache.commons:commons-lang3:3.2.1" + dependency "com.google.guava:guava:18.0" } } diff --git a/gradlew b/gradlew index 91a7e269..9db14b92 100644 --- a/gradlew +++ b/gradlew @@ -12,7 +12,7 @@ DEFAULT_JVM_OPTS="" APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` -# Use the maximum available, or set MAX_FD != -1 to use that value. +# Use the maximum available, or set MAX_FD != -1 to use that header. MAX_FD="maximum" warn ( ) { diff --git a/src/main/java/io/github/robwin/markup/builder/AbstractMarkupDocBuilder.java b/src/main/java/io/github/robwin/markup/builder/AbstractMarkupDocBuilder.java index 685ca28f..aaacc4b5 100644 --- a/src/main/java/io/github/robwin/markup/builder/AbstractMarkupDocBuilder.java +++ b/src/main/java/io/github/robwin/markup/builder/AbstractMarkupDocBuilder.java @@ -38,7 +38,7 @@ public abstract class AbstractMarkupDocBuilder implements MarkupDocBuilder { protected Logger logger = LoggerFactory.getLogger(getClass()); protected void documentTitle(Markup markup, String title){ - documentBuilder.append(newLine).append(markup).append(title).append(newLine).append(newLine); + documentBuilder.append(markup).append(title).append(newLine).append(newLine); } protected void documentTitleWithAttributes(Markup markup, String title){ @@ -115,6 +115,11 @@ public abstract class AbstractMarkupDocBuilder implements MarkupDocBuilder { return this; } + @Override + public MarkupDocBuilder table(List> cells) { + return tableWithColumnSpecs(null, cells); + } + @Override public String toString(){ return documentBuilder.toString(); diff --git a/src/main/java/io/github/robwin/markup/builder/MarkupDocBuilder.java b/src/main/java/io/github/robwin/markup/builder/MarkupDocBuilder.java index 928229a1..c23997ed 100644 --- a/src/main/java/io/github/robwin/markup/builder/MarkupDocBuilder.java +++ b/src/main/java/io/github/robwin/markup/builder/MarkupDocBuilder.java @@ -56,6 +56,10 @@ public interface MarkupDocBuilder { @Deprecated MarkupDocBuilder tableWithHeaderRow(List rowsInPSV); + MarkupDocBuilder table(List> cells); + + MarkupDocBuilder tableWithColumnSpecs(List headers, List> cells); + MarkupDocBuilder anchor(String anchor); /** @@ -84,4 +88,21 @@ public interface MarkupDocBuilder { */ void writeToFile(String directory, String fileName, Charset charset) throws IOException; + class TableColumnSpec { + public String header; + public Integer widthRatio = 0; + public TableColumnSpec() {} + public TableColumnSpec(String header, Integer widthRatio) { + this.header = header; + this.widthRatio = widthRatio; + } + public TableColumnSpec withHeader(String header) { + this.header = header; + return this; + } + public TableColumnSpec withWidthRatio(Integer widthRatio) { + this.widthRatio = widthRatio; + return this; + } + } } diff --git a/src/main/java/io/github/robwin/markup/builder/asciidoc/AsciiDoc.java b/src/main/java/io/github/robwin/markup/builder/asciidoc/AsciiDoc.java index b2b6192b..f75a34d8 100644 --- a/src/main/java/io/github/robwin/markup/builder/asciidoc/AsciiDoc.java +++ b/src/main/java/io/github/robwin/markup/builder/asciidoc/AsciiDoc.java @@ -28,6 +28,7 @@ public enum AsciiDoc implements Markup { LABELED(":: "), TABLE("|==="), TABLE_COLUMN_DELIMITER("|"), + TABLE_COLUMN_DELIMITER_ESCAPE("\\|"), // AsciiDoctor supports both \| and {vbar} LISTING("----"), HARDBREAKS(":hardbreaks:"), DOCUMENT_TITLE("= "), diff --git a/src/main/java/io/github/robwin/markup/builder/asciidoc/AsciiDocBuilder.java b/src/main/java/io/github/robwin/markup/builder/asciidoc/AsciiDocBuilder.java index 85b6d753..9dc1eb98 100644 --- a/src/main/java/io/github/robwin/markup/builder/asciidoc/AsciiDocBuilder.java +++ b/src/main/java/io/github/robwin/markup/builder/asciidoc/AsciiDocBuilder.java @@ -18,14 +18,21 @@ */ package io.github.robwin.markup.builder.asciidoc; +import com.google.common.base.Function; +import com.google.common.collect.Collections2; import io.github.robwin.markup.builder.AbstractMarkupDocBuilder; import io.github.robwin.markup.builder.MarkupDocBuilder; +import org.apache.commons.collections.CollectionUtils; import java.io.IOException; import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.regex.Pattern; +import static org.apache.commons.lang3.StringUtils.*; + /** * @author Robert Winkler */ @@ -138,6 +145,51 @@ public class AsciiDocBuilder extends AbstractMarkupDocBuilder { return this; } + private String escapeTableCell(String cell) { + return cell.replace(AsciiDoc.TABLE_COLUMN_DELIMITER.toString(), AsciiDoc.TABLE_COLUMN_DELIMITER_ESCAPE.toString()); + } + + @Override + public MarkupDocBuilder tableWithColumnSpecs(List columns, List> cells) { + + Boolean hasHeader = false; + List options = new ArrayList<>(); + List cols = new ArrayList<>(); + if (CollectionUtils.isNotEmpty(columns)) { + for (TableColumnSpec col : columns) { + if (!hasHeader && isNotBlank(col.header)) { + options.add("header"); + hasHeader = true; + } + cols.add(String.valueOf(col.widthRatio)); + } + } + + newLine(); + documentBuilder.append("[options=\"" + join(options, ",") + "\", cols=\"" + join(cols, ",") + "\"]").append(newLine); + documentBuilder.append(AsciiDoc.TABLE).append(newLine); + if (hasHeader) { + Collection headerList = Collections2.transform(columns, new Function() { + public String apply(final TableColumnSpec header) { + return escapeTableCell(defaultString(header.header)); + } + }); + documentBuilder.append(AsciiDoc.TABLE_COLUMN_DELIMITER).append(join(headerList, AsciiDoc.TABLE_COLUMN_DELIMITER.toString())).append(newLine); + + } + for (List row : cells) { + Collection cellList = Collections2.transform(row, new Function() { + public String apply(final String cell) { + return escapeTableCell(cell); + } + }); + documentBuilder.append(AsciiDoc.TABLE_COLUMN_DELIMITER).append(join(cellList, AsciiDoc.TABLE_COLUMN_DELIMITER.toString())).append(newLine); + } + documentBuilder.append(AsciiDoc.TABLE).append(newLine); + newLine(); + return this; + } + @Override public void writeToFile(String directory, String fileName, Charset charset) throws IOException { writeToFileWithExtension(directory, fileName + "." + ASCIIDOC_FILE_EXTENSION, charset); diff --git a/src/main/java/io/github/robwin/markup/builder/markdown/Markdown.java b/src/main/java/io/github/robwin/markup/builder/markdown/Markdown.java index f980150c..e290629b 100644 --- a/src/main/java/io/github/robwin/markup/builder/markdown/Markdown.java +++ b/src/main/java/io/github/robwin/markup/builder/markdown/Markdown.java @@ -26,6 +26,7 @@ import io.github.robwin.markup.builder.Markup; public enum Markdown implements Markup { HARDBREAKS(""), TABLE_COLUMN_DELIMITER("|"), + TABLE_COLUMN_DELIMITER_ESCAPE("\\|"), TABLE_ROW("-"), LISTING("```"), DOCUMENT_TITLE("# "), diff --git a/src/main/java/io/github/robwin/markup/builder/markdown/MarkdownBuilder.java b/src/main/java/io/github/robwin/markup/builder/markdown/MarkdownBuilder.java index 5e748a03..aae1a161 100644 --- a/src/main/java/io/github/robwin/markup/builder/markdown/MarkdownBuilder.java +++ b/src/main/java/io/github/robwin/markup/builder/markdown/MarkdownBuilder.java @@ -18,14 +18,22 @@ */ package io.github.robwin.markup.builder.markdown; +import com.google.common.base.Function; +import com.google.common.collect.Collections2; import io.github.robwin.markup.builder.AbstractMarkupDocBuilder; import io.github.robwin.markup.builder.MarkupDocBuilder; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; import java.io.IOException; import java.nio.charset.Charset; import java.util.Arrays; +import java.util.Collection; import java.util.List; +import static org.apache.commons.lang3.StringUtils.defaultString; +import static org.apache.commons.lang3.StringUtils.join; + /** * @author Robert Winkler */ @@ -156,6 +164,43 @@ public class MarkdownBuilder extends AbstractMarkupDocBuilder return this; } + private String escapeTableCell(String cell) { + return cell.replace(Markdown.TABLE_COLUMN_DELIMITER.toString(), Markdown.TABLE_COLUMN_DELIMITER_ESCAPE.toString()); + } + + @Override + public MarkupDocBuilder tableWithColumnSpecs(List columns, List> cells) { + if (CollectionUtils.isEmpty(columns)) + throw new RuntimeException("Header is mandatory in Markdown"); + + newLine(); + Collection headerList = Collections2.transform(columns, new Function() { + public String apply(final TableColumnSpec header) { + return escapeTableCell(defaultString(header.header)); + } + }); + documentBuilder.append(Markdown.TABLE_COLUMN_DELIMITER).append(join(headerList, Markdown.TABLE_COLUMN_DELIMITER.toString())).append(Markdown.TABLE_COLUMN_DELIMITER).append(newLine); + + documentBuilder.append(Markdown.TABLE_COLUMN_DELIMITER); + for (TableColumnSpec col : columns) { + documentBuilder.append(StringUtils.repeat(Markdown.TABLE_ROW.toString(), 3)); + documentBuilder.append(Markdown.TABLE_COLUMN_DELIMITER); + } + documentBuilder.append(newLine); + + for (List row : cells) { + Collection cellList = Collections2.transform(row, new Function() { + public String apply(final String cell) { + return escapeTableCell(cell); + } + }); + documentBuilder.append(Markdown.TABLE_COLUMN_DELIMITER).append(join(cellList, Markdown.TABLE_COLUMN_DELIMITER.toString())).append(Markdown.TABLE_COLUMN_DELIMITER).append(newLine); + } + newLine(); + + return this; + } + @Override public void writeToFile(String directory, String fileName, Charset charset) throws IOException { writeToFileWithExtension(directory, fileName + "." + MARKDOWN_FILE_EXTENSION, charset); diff --git a/src/test/java/io/github/robwin/markup/builder/MarkupDocBuilderTest.java b/src/test/java/io/github/robwin/markup/builder/MarkupDocBuilderTest.java index 59d51c2b..ee91eccd 100644 --- a/src/test/java/io/github/robwin/markup/builder/MarkupDocBuilderTest.java +++ b/src/test/java/io/github/robwin/markup/builder/MarkupDocBuilderTest.java @@ -33,6 +33,9 @@ import java.util.List; public class MarkupDocBuilderTest { List tableRowsInPSV; + List tableColumns; + List> tableCells; + @Before public void setUp(){ @@ -40,6 +43,14 @@ public class MarkupDocBuilderTest { tableRowsInPSV.add("Header 1 | Header 2 | Header2"); tableRowsInPSV.add("Row 1, Column 1 | Row 1, Column 2 | Row 1, Column 3"); tableRowsInPSV.add("Row 2, Column 1 | Row 2, Column 2 | Row 2, Column 3"); + + tableColumns = Arrays.asList( + new MarkupDocBuilder.TableColumnSpec().withHeader("Header1"), + new MarkupDocBuilder.TableColumnSpec().withWidthRatio(2), + new MarkupDocBuilder.TableColumnSpec().withHeader("Header3").withWidthRatio(1)); + tableCells = new ArrayList<>(); + tableCells.add(Arrays.asList("Row 1 | Column 1", "Row 1 | Column 2", "Row 1 | Column 3")); + tableCells.add(Arrays.asList("Row 2 | Column 1", "Row 2 | Column 2", "Row 2 | Column 3")); } @@ -55,15 +66,17 @@ public class MarkupDocBuilderTest { .listing("Source code listing") .source("MarkupDocBuilder builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.ASCIIDOC)", "java") .tableWithHeaderRow(tableRowsInPSV) + .table(tableCells) + .tableWithColumnSpecs(tableColumns, tableCells) .sectionTitleLevel1("Section Level 1b") .sectionTitleLevel2("Section Level 2b") .textLine("text line b") .boldTextLine("Bold text line b") .italicTextLine("Italic text line b") .unorderedList(Arrays.asList("Entry1", "Entry2", "Entry 2")) - .anchor("anchor") - .crossReference("anchor") - .crossReference("anchor", "text") + .anchor("anchor").newLine() + .crossReference("anchor").newLine() + .crossReference("anchor", "text").newLine() .writeToFile("build/tmp", "test", StandardCharsets.UTF_8); } @@ -79,15 +92,17 @@ public class MarkupDocBuilderTest { .listing("Source code listing") .source("MarkupDocBuilder builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.MARKDOWN)", "java") .tableWithHeaderRow(tableRowsInPSV) + //.table(tableCells) + .tableWithColumnSpecs(tableColumns, tableCells) .sectionTitleLevel1("Section Level 1b") .sectionTitleLevel2("Section Level 2b") .textLine("text line b") .boldTextLine("Bold text line b") .italicTextLine("Italic text line b") .unorderedList(Arrays.asList("Entry1", "Entry2", "Entry 2")) - .anchor("anchor") - .crossReference("anchor") - .crossReference("anchor", "text") + .anchor("anchor").newLine() + .crossReference("anchor").newLine() + .crossReference("anchor", "text").newLine() .writeToFile("build/tmp", "test", StandardCharsets.UTF_8); }