diff --git a/asciidoctorj-core/src/main/java/org/asciidoctor/ast/DescriptionListEntry.java b/asciidoctorj-core/src/main/java/org/asciidoctor/ast/DescriptionListEntry.java index bba3d9b25..9e6bbf2f6 100644 --- a/asciidoctorj-core/src/main/java/org/asciidoctor/ast/DescriptionListEntry.java +++ b/asciidoctorj-core/src/main/java/org/asciidoctor/ast/DescriptionListEntry.java @@ -6,4 +6,22 @@ public interface DescriptionListEntry { ListItem getDescription(); + /** + * Sets a new description for a description list item. + * Description list items are ordinary ListItems and can be created using the factory methods of + * a processor: + *
+     * class MyTreeprocessor extends Treeprocessor() {
+     *   public Document process(Document doc) {
+     *     final String newDescription = "A new description for this entry.";
+     *     DescriptionList dl = ...
+     *     DescriptionListEntry dlEntry = ...
+     *     dlEntry.setDescription(createListItem(dl, newDescription));
+     *     return doc;
+     *   }
+     * }
+ * @param description The new description for this description list entry, + */ + void setDescription(final ListItem description); + } diff --git a/asciidoctorj-core/src/main/java/org/asciidoctor/ast/impl/DescriptionListEntryImpl.java b/asciidoctorj-core/src/main/java/org/asciidoctor/ast/impl/DescriptionListEntryImpl.java index 32d11d22a..edf86b3a1 100644 --- a/asciidoctorj-core/src/main/java/org/asciidoctor/ast/impl/DescriptionListEntryImpl.java +++ b/asciidoctorj-core/src/main/java/org/asciidoctor/ast/impl/DescriptionListEntryImpl.java @@ -4,6 +4,7 @@ import org.asciidoctor.ast.ListItem; import org.asciidoctor.ast.NodeConverter; import org.asciidoctor.internal.RubyBlockListDecorator; +import org.asciidoctor.internal.RubyObjectWrapper; import org.jruby.RubyArray; import org.jruby.runtime.builtin.IRubyObject; @@ -26,7 +27,17 @@ public ListItem getDescription() { return firstItem == null ? null : (ListItem) NodeConverter.createASTNode(firstItem); } + public void setDescription(final ListItem description) { + setAt(1, description); + } + private Object getAt(int i) { return ((RubyArray) getRubyObject()).get(i); } + + private void setAt(int i, Object object) { + ((RubyArray) getRubyObject()).set(i, RubyObjectWrapper.class.cast(object).getRubyObject()); + } + + } diff --git a/asciidoctorj-core/src/main/java/org/asciidoctor/extension/Processor.java b/asciidoctorj-core/src/main/java/org/asciidoctor/extension/Processor.java index e2278ecb2..36c52f110 100644 --- a/asciidoctorj-core/src/main/java/org/asciidoctor/extension/Processor.java +++ b/asciidoctorj-core/src/main/java/org/asciidoctor/extension/Processor.java @@ -1,10 +1,24 @@ package org.asciidoctor.extension; import org.asciidoctor.Options; -import org.asciidoctor.ast.*; +import org.asciidoctor.ast.Block; +import org.asciidoctor.ast.Cell; +import org.asciidoctor.ast.Column; +import org.asciidoctor.ast.ContentModel; +import org.asciidoctor.ast.ContentNode; +import org.asciidoctor.ast.Document; +import org.asciidoctor.ast.ListItem; +import org.asciidoctor.ast.NodeConverter; +import org.asciidoctor.ast.PhraseNode; +import org.asciidoctor.ast.Row; +import org.asciidoctor.ast.Section; +import org.asciidoctor.ast.StructuralNode; +import org.asciidoctor.ast.Table; import org.asciidoctor.ast.impl.ColumnImpl; import org.asciidoctor.ast.impl.ContentNodeImpl; +import org.asciidoctor.ast.impl.DescriptionListImpl; import org.asciidoctor.ast.impl.DocumentImpl; +import org.asciidoctor.ast.impl.ListImpl; import org.asciidoctor.ast.impl.RowImpl; import org.asciidoctor.ast.impl.StructuralNodeImpl; import org.asciidoctor.internal.JRubyRuntimeContext; @@ -21,7 +35,14 @@ import java.util.List; import java.util.Map; -import static org.asciidoctor.ast.NodeConverter.NodeType.*; +import static org.asciidoctor.ast.NodeConverter.NodeType.BLOCK_CLASS; +import static org.asciidoctor.ast.NodeConverter.NodeType.DOCUMENT_CLASS; +import static org.asciidoctor.ast.NodeConverter.NodeType.INLINE_CLASS; +import static org.asciidoctor.ast.NodeConverter.NodeType.LIST_ITEM_CLASS; +import static org.asciidoctor.ast.NodeConverter.NodeType.SECTION_CLASS; +import static org.asciidoctor.ast.NodeConverter.NodeType.TABLE_CELL_CLASS; +import static org.asciidoctor.ast.NodeConverter.NodeType.TABLE_CLASS; +import static org.asciidoctor.ast.NodeConverter.NodeType.TABLE_COLUMN_CLASS; public class Processor { @@ -352,6 +373,18 @@ public Document createDocument(Document parentDocument) { return (Document) NodeConverter.createASTNode(runtime, DOCUMENT_CLASS, runtime.getNil(), options); } + public ListItem createListItem(final org.asciidoctor.ast.List parent, final String text) { + Ruby rubyRuntime = JRubyRuntimeContext.get(parent); + + return (ListItem) NodeConverter.createASTNode(rubyRuntime, LIST_ITEM_CLASS, ListImpl.class.cast(parent).getRubyObject(), rubyRuntime.newString(text)); + } + + public ListItem createListItem(final org.asciidoctor.ast.DescriptionList parent, final String text) { + Ruby rubyRuntime = JRubyRuntimeContext.get(parent); + + return (ListItem) NodeConverter.createASTNode(rubyRuntime, LIST_ITEM_CLASS, DescriptionListImpl.class.cast(parent).getRubyObject(), rubyRuntime.newString(text)); + } + /** * Parses the given raw asciidoctor content, parses it and appends it as children to the given parent block. *

The following example will add two paragraphs with the role {@code newcontent} to all top diff --git a/asciidoctorj-core/src/test/groovy/org/asciidoctor/WhenADocumentContainsADefinitionList.groovy b/asciidoctorj-core/src/test/groovy/org/asciidoctor/WhenADocumentContainsADefinitionList.groovy index c8c449bbc..c10cf998a 100644 --- a/asciidoctorj-core/src/test/groovy/org/asciidoctor/WhenADocumentContainsADefinitionList.groovy +++ b/asciidoctorj-core/src/test/groovy/org/asciidoctor/WhenADocumentContainsADefinitionList.groovy @@ -6,14 +6,17 @@ import org.asciidoctor.ast.DescriptionListEntry import org.asciidoctor.ast.Document import org.asciidoctor.ast.ListItem import org.asciidoctor.converter.StringConverter +import org.asciidoctor.extension.Treeprocessor import org.jboss.arquillian.spock.ArquillianSputnik import org.jboss.arquillian.test.api.ArquillianResource +import org.jsoup.Jsoup import org.junit.runner.RunWith import spock.lang.Specification @RunWith(ArquillianSputnik) class WhenADocumentContainsADefinitionList extends Specification { + static final String TAG_DD = 'dd' @ArquillianResource private Asciidoctor asciidoctor @@ -142,4 +145,31 @@ A very nice description ''' } + def 'a processor should be able to set the description of a description list'() { + + given: + String document = '''= Test document + +Item A:: + Replace me +''' + String newDescription = 'A nice description' + + when: + asciidoctor.javaExtensionRegistry().treeprocessor(new Treeprocessor() { + @Override + Document process(Document doc) { + DescriptionList dl = doc.getBlocks().get(0) + DescriptionListEntry dlEntry = dl.items[0] + dlEntry.setDescription(createListItem(dl, newDescription)) + doc + } + }) + String result = asciidoctor.convert(document, OptionsBuilder.options().headerFooter(false).asMap()) + + then: + org.jsoup.nodes.Document htmlDoc = Jsoup.parse(result) + htmlDoc.getElementsByTag(TAG_DD).size() == 1 + htmlDoc.getElementsByTag(TAG_DD)[0].text() == newDescription + } }