Ensure that all nodes for a snippet refer to main document
Previously, when the operation block macro rendered the fragment for a snippet, every top-level block in the fragment had its parent set. Setting the parent has the side-effect of also setting the block's document to be that of its parent. This meant that every top-level block's document referred to the main document, but any descendents were left with their document referring to the fragment document. This did not cause a problem with the HTML backend (which does not consider a block's document) but the PDF backend does consider a block's document resulting in the descendents being omitted from the generated PDF. This commit updates the operation block macro to set the parent of every block in the fragment to its correct value. This has the side-effect of causing the block to update its document reference to point to the main document. Closes gh-396
This commit is contained in:
@@ -72,7 +72,9 @@ subprojects {
|
||||
dependency 'javax.validation:validation-api:1.1.0.Final'
|
||||
dependency 'junit:junit:4.12'
|
||||
dependency 'io.rest-assured:rest-assured:3.0.2'
|
||||
dependency 'org.asciidoctor:asciidoctorj:1.5.3.1'
|
||||
dependency 'org.apache.pdfbox:pdfbox:2.0.6'
|
||||
dependency 'org.asciidoctor:asciidoctorj:1.5.5'
|
||||
dependency 'org.asciidoctor:asciidoctorj-pdf:1.5.0-alpha.15'
|
||||
dependency 'org.hamcrest:hamcrest-core:1.3'
|
||||
dependency 'org.hamcrest:hamcrest-library:1.3'
|
||||
dependency 'org.hibernate:hibernate-validator:5.2.2.Final'
|
||||
|
||||
@@ -3,6 +3,8 @@ description = 'Asciidoctor extensions for Spring REST Docs'
|
||||
dependencies {
|
||||
provided 'org.asciidoctor:asciidoctorj'
|
||||
testCompile 'junit:junit'
|
||||
testCompile 'org.apache.pdfbox:pdfbox'
|
||||
testCompile 'org.asciidoctor:asciidoctorj'
|
||||
testCompile 'org.springframework:spring-core'
|
||||
testRuntime 'org.asciidoctor:asciidoctorj-pdf'
|
||||
}
|
||||
@@ -47,13 +47,15 @@ class OperationBlockMacro < Asciidoctor::Extensions::BlockMacroProcessor
|
||||
|
||||
def add_blocks(content, doc, parent)
|
||||
options = { safe: doc.options[:safe],
|
||||
attributes: { 'fragment' => '',
|
||||
'projectdir' => doc.attr(:projectdir) } }
|
||||
attributes: { 'projectdir' => doc.attr(:projectdir) } }
|
||||
fragment = Asciidoctor.load content, options
|
||||
fragment.blocks.each do |b|
|
||||
b.parent = parent
|
||||
parent << b
|
||||
end
|
||||
parent.find_by.each do |b|
|
||||
b.parent = b.parent unless b.is_a? Asciidoctor::Document
|
||||
end
|
||||
end
|
||||
|
||||
def snippets_to_include(snippet_names, snippets_dir, operation)
|
||||
|
||||
@@ -22,7 +22,14 @@ import java.net.URISyntaxException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.pdfbox.contentstream.PDFStreamEngine;
|
||||
import org.apache.pdfbox.contentstream.operator.Operator;
|
||||
import org.apache.pdfbox.cos.COSBase;
|
||||
import org.apache.pdfbox.cos.COSString;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.asciidoctor.Asciidoctor;
|
||||
import org.asciidoctor.Attributes;
|
||||
import org.asciidoctor.Options;
|
||||
@@ -33,6 +40,7 @@ import org.junit.Test;
|
||||
import org.springframework.util.FileSystemUtils;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.hasItems;
|
||||
import static org.hamcrest.CoreMatchers.startsWith;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
@@ -62,12 +70,38 @@ public class OperationBlockMacroTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleSnippetInclude() throws Exception {
|
||||
public void codeBlockSnippetInclude() throws Exception {
|
||||
String result = this.asciidoctor.convert(
|
||||
"operation::some-operation[snippets='curl-request']", this.options);
|
||||
assertThat(result, equalTo(getExpectedContentFromFile("snippet-simple")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void codeBlockSnippetIncludeWithPdfBackend() throws Exception {
|
||||
File output = configurePdfOutput();
|
||||
this.asciidoctor.convert("operation::some-operation[snippets='curl-request']",
|
||||
this.options);
|
||||
assertThat(extractStrings(output),
|
||||
hasItems("Curl request", "$ curl 'http://localhost:8080/' -i", "1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tableSnippetInclude() throws Exception {
|
||||
String result = this.asciidoctor.convert(
|
||||
"operation::some-operation[snippets='response-fields']", this.options);
|
||||
assertThat(result, equalTo(getExpectedContentFromFile("snippet-table")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tableSnippetIncludeWithPdfBackend() throws Exception {
|
||||
File output = configurePdfOutput();
|
||||
this.asciidoctor.convert("operation::some-operation[snippets='response-fields']",
|
||||
this.options);
|
||||
assertThat(extractStrings(output),
|
||||
hasItems("Response fields", "Path", "Type", "Description", "a", "Object",
|
||||
"one", "a.b", "Number", "two", "a.c", "String", "three", "1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void includeSnippetInSection() throws Exception {
|
||||
String result = this.asciidoctor.convert(
|
||||
@@ -76,6 +110,16 @@ public class OperationBlockMacroTests {
|
||||
assertThat(result, equalTo(getExpectedContentFromFile("snippet-in-section")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void includeSnippetInSectionWithPdfBackend() throws Exception {
|
||||
File output = configurePdfOutput();
|
||||
this.asciidoctor.convert(
|
||||
"== Section\n" + "operation::some-operation[snippets='curl-request']",
|
||||
this.options);
|
||||
assertThat(extractStrings(output), hasItems("Section", "Curl request",
|
||||
"$ curl 'http://localhost:8080/' -i", "1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void includeMultipleSnippets() throws Exception {
|
||||
String result = this.asciidoctor.convert(
|
||||
@@ -163,4 +207,41 @@ public class OperationBlockMacroTests {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
private File configurePdfOutput() {
|
||||
this.options.setBackend("pdf");
|
||||
File output = new File("build/output.pdf");
|
||||
this.options.setToFile(output.getAbsolutePath());
|
||||
return output;
|
||||
}
|
||||
|
||||
private List<String> extractStrings(File pdfFile) throws IOException {
|
||||
PDDocument pdf = PDDocument.load(pdfFile);
|
||||
assertThat(pdf.getNumberOfPages(), equalTo(1));
|
||||
StringExtractor stringExtractor = new StringExtractor();
|
||||
stringExtractor.processPage(pdf.getPage(0));
|
||||
return stringExtractor.getStrings();
|
||||
}
|
||||
|
||||
private static final class StringExtractor extends PDFStreamEngine {
|
||||
|
||||
private final List<String> strings = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
protected void processOperator(Operator operator, List<COSBase> operands)
|
||||
throws IOException {
|
||||
if ("Tj".equals(operator.getName())) {
|
||||
for (COSBase operand : operands) {
|
||||
if (operand instanceof COSString) {
|
||||
this.strings.add((((COSString) operand).getASCII()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> getStrings() {
|
||||
return this.strings;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,4 +28,40 @@ Host: localhost:8080</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="_response_fields">Response fields</h2>
|
||||
<div class="sectionbody">
|
||||
<table class="tableblock frame-all grid-all spread">
|
||||
<colgroup>
|
||||
<col style="width: 33.3333%;">
|
||||
<col style="width: 33.3333%;">
|
||||
<col style="width: 33.3334%;">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="tableblock halign-left valign-top">Path</th>
|
||||
<th class="tableblock halign-left valign-top">Type</th>
|
||||
<th class="tableblock halign-left valign-top">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>a</code></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Object</code></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">one</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>a.b</code></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Number</code></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">two</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>a.c</code></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>String</code></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">three</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,36 @@
|
||||
<div class="sect1">
|
||||
<h2 id="_response_fields">Response fields</h2>
|
||||
<div class="sectionbody">
|
||||
<table class="tableblock frame-all grid-all spread">
|
||||
<colgroup>
|
||||
<col style="width: 33.3333%;">
|
||||
<col style="width: 33.3333%;">
|
||||
<col style="width: 33.3334%;">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="tableblock halign-left valign-top">Path</th>
|
||||
<th class="tableblock halign-left valign-top">Type</th>
|
||||
<th class="tableblock halign-left valign-top">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>a</code></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Object</code></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">one</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>a.b</code></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Number</code></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">two</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>a.c</code></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>String</code></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">three</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,16 @@
|
||||
|===
|
||||
|Path|Type|Description
|
||||
|
||||
|`a`
|
||||
|`Object`
|
||||
|one
|
||||
|
||||
|`a.b`
|
||||
|`Number`
|
||||
|two
|
||||
|
||||
|`a.c`
|
||||
|`String`
|
||||
|three
|
||||
|
||||
|===
|
||||
Reference in New Issue
Block a user