Fixes Explicit unregistration of extensions.
MODIFY
README.adoc
README.adoc
@@ -1380,6 +1380,30 @@ String content = asciidoctor.convertFile(new File(
You can unregister all extensions by calling the `org.asciidoctor.Asciidoctor.unregisterAllExtensions()` method.
+Additionally, since AsciidoctorJ 1.5.6.1 it is possible to unregister specific extensions when using the ExtensionGroup API.
+This allows to register and unregister a group of extensions as a whole:
+
+[source,java]
+----
+BlockProcessor extension1 = ...
+Treeprocessor extension2 = ...
+ExtensionGroup extensionGroup =
+ asciidoctor.createGroup()
+ .block(extension1)
+ .treeprocessor(extension2);
+
+asciidoctor.convert(...) // <1>
+
+extensionGroup.register();
+asciidoctor.convert(); // <2>
+
+extensionGroup.register();
+asciidoctor.convert(); // <3>
+----
+<1> Convert a document without the extensions active because they were not registered yet.
+<2> Convert with extensions active after registration.
+<3> Convert without extensions active after the extensions were unregistered.
+
=== Ruby extensions
You can even register extensions written in Ruby using AsciidoctorJ.

MODIFY
asciidoctorj-core/src/main/java/org/asciidoctor/Asciidoctor.java
asciidoctorj-core/src/main/java/org/asciidoctor/Asciidoctor.java
@@ -13,6 +13,7 @@ import org.asciidoctor.ast.DocumentHeader;
import org.asciidoctor.ast.DocumentRuby;
import org.asciidoctor.ast.StructuredDocument;
import org.asciidoctor.converter.JavaConverterRegistry;
+import org.asciidoctor.extension.ExtensionGroup;
import org.asciidoctor.extension.JavaExtensionRegistry;
import org.asciidoctor.extension.RubyExtensionRegistry;
import org.asciidoctor.internal.JRubyAsciidoctor;
@@ -634,6 +635,17 @@ public interface Asciidoctor {
*/
JavaConverterRegistry javaConverterRegistry();
+ /**
+ * Creates an ExtensionGroup that can be used to register and unregister a group of extensions.
+ * @return
+ */
+ ExtensionGroup createGroup();
+
+ /**
+ * Creates an ExtensionGroup that can be used to register and unregister a group of extensions.
+ * @return
+ */
+ ExtensionGroup createGroup(String groupName);
/**
* Unregister all registered extensions.
*/

ADD
asciidoctorj-core/src/main/java/org/asciidoctor/extension/ExtensionGroup.java
+package org.asciidoctor.extension;
+
+
+import java.io.InputStream;
+
+/**
+ * An ExtensionGroup allows to collectively register and unregister extensions.
+ * All extensions are registered lazily and are not effective before a call to {@link #register()}.
+ *
+ * <p>Example:
+ * <code><pre>
+ * ExtensionGroup group = asciidoctor.createGroup();
+ * group.block(myBlock).preprocessor(mypreprocessor);
+ *
+ * // Convert with extensions
+ * group.register();
+ * asciidoctor.convert(...);
+ * group.unregister();
+ *
+ * // Convert without extensions
+ * asciidoctor.convert(...);
+ * </pre></code></p>
+ */
+public interface ExtensionGroup {
+
+ public void register();
+
+ public void unregister();
+
+ public ExtensionGroup docinfoProcessor(Class<? extends DocinfoProcessor> docInfoProcessor);
+ public ExtensionGroup docinfoProcessor(DocinfoProcessor docInfoProcessor);
+ public ExtensionGroup docinfoProcessor(String docInfoProcessor);
+
+ public ExtensionGroup preprocessor(Class<? extends Preprocessor> preprocessor);
+ public ExtensionGroup preprocessor(Preprocessor preprocessor);
+ public ExtensionGroup preprocessor(String preprocessor);
+
+ public ExtensionGroup postprocessor(String postprocessor);
+ public ExtensionGroup postprocessor(Class<? extends Postprocessor> postprocessor);
+ public ExtensionGroup postprocessor(Postprocessor postprocesor);
+
+ public ExtensionGroup includeProcessor(String includeProcessor);
+ public ExtensionGroup includeProcessor(Class<? extends IncludeProcessor> includeProcessor);
+ public ExtensionGroup includeProcessor(IncludeProcessor includeProcessor);
+
+ public ExtensionGroup treeprocessor(Treeprocessor treeprocessor);
+ public ExtensionGroup treeprocessor(Class<? extends Treeprocessor> treeProcessor);
+ public ExtensionGroup treeprocessor(String treeProcessor);
+
+ public ExtensionGroup block(String blockName, String blockProcessor);
+ public ExtensionGroup block(String blockName, Class<? extends BlockProcessor> blockProcessor);
+ public ExtensionGroup block(BlockProcessor blockProcessor);
+ public ExtensionGroup block(String blockName, BlockProcessor blockProcessor);
+
+ public ExtensionGroup blockMacro(String blockName, Class<? extends BlockMacroProcessor> blockMacroProcessor);
+ public ExtensionGroup blockMacro(String blockName, String blockMacroProcessor);
+ public ExtensionGroup blockMacro(BlockMacroProcessor blockMacroProcessor);
+
+ public ExtensionGroup inlineMacro(InlineMacroProcessor inlineMacroProcessor);
+ public ExtensionGroup inlineMacro(String blockName, Class<? extends InlineMacroProcessor> inlineMacroProcessor);
+ public ExtensionGroup inlineMacro(String blockName, String inlineMacroProcessor);
+
+ public ExtensionGroup requireRubyLibrary(String requiredLibrary);
+ public ExtensionGroup loadRubyClass(InputStream rubyClassStream);
+
+ public ExtensionGroup rubyPreprocessor(String preprocessor);
+ public ExtensionGroup rubyPostprocessor(String postprocessor);
+ public ExtensionGroup rubyDocinfoProcessor(String docinfoProcessor);
+ public ExtensionGroup rubyIncludeProcessor(String includeProcessor);
+ public ExtensionGroup rubyTreeprocessor(String treeProcessor);
+ public ExtensionGroup rubyBlock(String blockName, String blockProcessor);
+ public ExtensionGroup rubyBlockMacro(String blockName, String blockMacroProcessor);
+ public ExtensionGroup rubyInlineMacro(String blockName, String inlineMacroProcessor);
+}

MODIFY
asciidoctorj-core/src/main/java/org/asciidoctor/extension/RubyExtensionRegistry.java
asciidoctorj-core/src/main/java/org/asciidoctor/extension/RubyExtensionRegistry.java
@@ -9,6 +9,7 @@ import org.jruby.Ruby;
public class RubyExtensionRegistry {
private AsciidoctorModule asciidoctorModule;
+
private Ruby rubyRuntime;
public RubyExtensionRegistry(AsciidoctorModule asciidoctorModule,
@@ -33,8 +34,8 @@ public class RubyExtensionRegistry {
return this;
}
- public RubyExtensionRegistry postprocessor(String postprocesor) {
- this.asciidoctorModule.postprocessor(postprocesor);
+ public RubyExtensionRegistry postprocessor(String postprocessor) {
+ this.asciidoctorModule.postprocessor(postprocessor);
return this;
}
@@ -72,5 +73,4 @@ public class RubyExtensionRegistry {
inlineMacroProcessor, RubyUtils.toSymbol(rubyRuntime, blockName));
return this;
}
-
}
\ No newline at end of file

MODIFY
asciidoctorj-core/src/main/java/org/asciidoctor/internal/AsciidoctorModule.java
asciidoctorj-core/src/main/java/org/asciidoctor/internal/AsciidoctorModule.java
@@ -13,38 +13,63 @@ import org.jruby.RubyHash;
public interface AsciidoctorModule {
void preprocessor(String preprocessorClassName);
+ void preprocessor(String preprocessorClassName, String registrationName);
void preprocessor(RubyClass preprocessorClassName);
+ void preprocessor(RubyClass preprocessorClassName, String registrationName);
void preprocessor(Preprocessor preprocessor);
+ void preprocessor(Preprocessor preprocessor, String registrationName);
void postprocessor(String postprocessorClassName);
+ void postprocessor(String postprocessorClassName, String registrationName);
void postprocessor(RubyClass postprocessorClassName);
+ void postprocessor(RubyClass postprocessorClassName, String registrationName);
void postprocessor(Postprocessor postprocessor);
+ void postprocessor(Postprocessor postprocessor, String registrationName);
void treeprocessor(String treeprocessor);
+ void treeprocessor(String treeprocessor, String registrationName);
void treeprocessor(RubyClass treeprocessorClassName);
+ void treeprocessor(RubyClass treeprocessorClassName, String registrationName);
void treeprocessor(Treeprocessor treeprocessorClassName);
+ void treeprocessor(Treeprocessor treeprocessorClassName, String registrationName);
void include_processor(String includeProcessorClassName);
+ void include_processor(String includeProcessorClassName, String registrationName);
void include_processor(RubyClass includeProcessorClassName);
+ void include_processor(RubyClass includeProcessorClassName, String registrationName);
void include_processor(IncludeProcessor includeProcessor);
+ void include_processor(IncludeProcessor includeProcessor, String registrationName);
void block_processor(String blockClassName, Object blockName);
+ void block_processor(String blockClassName, Object blockName, String registrationName);
void block_processor(RubyClass blockClass, Object blockName);
+ void block_processor(RubyClass blockClass, Object blockName, String registrationName);
void block_processor(BlockProcessor blockInstance, Object blockName);
+ void block_processor(BlockProcessor blockInstance, Object blockName, String registrationName);
void block_macro(String blockMacroClassName, Object blockName);
+ void block_macro(String blockMacroClassName, Object blockName, String registrationName);
void block_macro(Class<BlockMacroProcessor> blockMacroClass, Object blockName);
+ void block_macro(Class<BlockMacroProcessor> blockMacroClass, Object blockName, String registrationName);
void block_macro(BlockMacroProcessor blockMacroInstance, Object blockName);
+ void block_macro(BlockMacroProcessor blockMacroInstance, Object blockName, String registrationName);
void inline_macro(String blockClassName, Object blockSymbol);
+ void inline_macro(String blockClassName, Object blockSymbol, String registrationName);
void inline_macro(RubyClass blockClassName, Object blockSymbol);
+ void inline_macro(RubyClass blockClassName, Object blockSymbol, String registrationName);
void inline_macro(InlineMacroProcessor blockClassName, Object blockSymbol);
+ void inline_macro(InlineMacroProcessor blockClassName, Object blockSymbol, String registrationName);
void docinfo_processor(String docInfoClassName);
+ void docinfo_processor(String docInfoClassName, String registrationName);
void docinfo_processor(RubyClass docInfoClassName);
+ void docinfo_processor(RubyClass docInfoClassName, String registrationName);
void docinfo_processor(DocinfoProcessor docInfoClassName);
+ void docinfo_processor(DocinfoProcessor docInfoClassName, String registrationName);
void unregister_all_extensions();
+ void unregister_extension(String groupName);
Object convert(String content, Map<String, Object> options);
Object convertFile(String filename, Map<String, Object> options);

ADD
asciidoctorj-core/src/main/java/org/asciidoctor/internal/ExtensionGroupImpl.java
+package org.asciidoctor.internal;
+
+import org.asciidoctor.extension.BlockMacroProcessor;
+import org.asciidoctor.extension.BlockProcessor;
+import org.asciidoctor.extension.DocinfoProcessor;
+import org.asciidoctor.extension.ExtensionGroup;
+import org.asciidoctor.extension.IncludeProcessor;
+import org.asciidoctor.extension.InlineMacroProcessor;
+import org.asciidoctor.extension.Postprocessor;
+import org.asciidoctor.extension.Preprocessor;
+import org.asciidoctor.extension.Treeprocessor;
+import org.jruby.Ruby;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by robertpanzer on 21.07.17.
+ */
+public class ExtensionGroupImpl implements ExtensionGroup {
+
+ private final JRubyAsciidoctor asciidoctor;
+
+ private final Ruby rubyRuntime;
+
+ private final AsciidoctorModule asciidoctorModule;
+
+ private final String groupName;
+
+ private final List<Runnable> registrations = new ArrayList<Runnable>();
+
+ public ExtensionGroupImpl(String groupName, JRubyAsciidoctor asciidoctor) {
+ this.groupName = groupName;
+ this.asciidoctor = asciidoctor;
+ this.rubyRuntime = asciidoctor.getRubyRuntime();
+ asciidoctorModule = asciidoctor.getAsciidoctorModule();
+ }
+
+ @Override
+ public void register() {
+ for (Runnable r: registrations) {
+ r.run();
+ }
+ }
+
+ @Override
+ public void unregister() {
+ asciidoctorModule.unregister_extension(groupName);
+ }
+
+ @Override
+ public ExtensionGroup docinfoProcessor(final Class<? extends DocinfoProcessor> docInfoProcessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ javaImport(rubyRuntime, docInfoProcessor);
+ asciidoctorModule.docinfo_processor(RubyUtils.toRubyClass(rubyRuntime, docInfoProcessor), groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup docinfoProcessor(final DocinfoProcessor docInfoProcessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ javaImport(rubyRuntime, docInfoProcessor.getClass());
+ asciidoctorModule.docinfo_processor(docInfoProcessor, groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup docinfoProcessor(final String docInfoProcessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ javaImport(rubyRuntime, docInfoProcessor);
+ asciidoctorModule.docinfo_processor(getClassName(docInfoProcessor), groupName);
+
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup preprocessor(final Class<? extends Preprocessor> preprocessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ javaImport(rubyRuntime, preprocessor);
+ asciidoctorModule.preprocessor(RubyUtils.toRubyClass(rubyRuntime, preprocessor), groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup preprocessor(final Preprocessor preprocessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ javaImport(rubyRuntime, preprocessor.getClass());
+ asciidoctorModule.preprocessor(preprocessor, groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup preprocessor(final String preprocessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ javaImport(rubyRuntime, preprocessor);
+ asciidoctorModule.preprocessor(getClassName(preprocessor), groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup postprocessor(final String postprocessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ javaImport(rubyRuntime, postprocessor);
+ asciidoctorModule.postprocessor(getClassName(postprocessor), groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup postprocessor(final Class<? extends Postprocessor> postprocessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ javaImport(rubyRuntime, postprocessor);
+ asciidoctorModule.postprocessor(RubyUtils.toRubyClass(rubyRuntime, postprocessor), groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup postprocessor(final Postprocessor postprocesor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ javaImport(rubyRuntime, postprocesor.getClass());
+ asciidoctorModule.postprocessor(postprocesor, groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup includeProcessor(final String includeProcessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ javaImport(rubyRuntime, includeProcessor);
+ asciidoctorModule.include_processor(getClassName(includeProcessor), groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup includeProcessor(final Class<? extends IncludeProcessor> includeProcessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ javaImport(rubyRuntime, includeProcessor);
+ asciidoctorModule.include_processor(RubyUtils.toRubyClass(rubyRuntime, includeProcessor), groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup includeProcessor(final IncludeProcessor includeProcessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ String importLine = getImportLine(includeProcessor.getClass());
+ javaImport(rubyRuntime, importLine);
+ asciidoctorModule.include_processor(includeProcessor, groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup treeprocessor(final Treeprocessor treeprocessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ javaImport(rubyRuntime, treeprocessor.getClass());
+ asciidoctorModule.treeprocessor(treeprocessor, groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup treeprocessor(final Class<? extends Treeprocessor> treeProcessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ javaImport(rubyRuntime, treeProcessor);
+ asciidoctorModule.treeprocessor(RubyUtils.toRubyClass(rubyRuntime, treeProcessor), groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup treeprocessor(final String treeProcessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ javaImport(rubyRuntime, treeProcessor);
+ asciidoctorModule.treeprocessor(getClassName(treeProcessor), groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup block(final String blockName, final String blockProcessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ javaImport(rubyRuntime, blockProcessor);
+
+ asciidoctorModule.block_processor(
+ getClassName(blockProcessor),
+ RubyUtils.toSymbol(rubyRuntime, blockName), groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup block(final String blockName, final Class<? extends BlockProcessor> blockProcessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ javaImport(rubyRuntime, blockProcessor);
+
+ asciidoctorModule.block_processor(
+ RubyUtils.toRubyClass(rubyRuntime, blockProcessor),
+ RubyUtils.toSymbol(rubyRuntime, blockName), groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup block(final BlockProcessor blockProcessor) {
+ block(blockProcessor.getName(), blockProcessor);
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup block(final String blockName, final BlockProcessor blockProcessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ javaImport(rubyRuntime, blockProcessor.getClass());
+
+ asciidoctorModule.block_processor(
+ blockProcessor,
+ RubyUtils.toSymbol(rubyRuntime, blockName), groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup blockMacro(final String blockName, final Class<? extends BlockMacroProcessor> blockMacroProcessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ javaImport(rubyRuntime, blockMacroProcessor);
+ asciidoctorModule.block_macro(
+ blockMacroProcessor.getSimpleName(),
+ RubyUtils.toSymbol(rubyRuntime, blockName), groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup blockMacro(final String blockName, final String blockMacroProcessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ javaImport(rubyRuntime, blockMacroProcessor);
+ asciidoctorModule.block_macro(
+ getClassName(blockMacroProcessor),
+ RubyUtils.toSymbol(rubyRuntime, blockName), groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup blockMacro(final BlockMacroProcessor blockMacroProcessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ javaImport(rubyRuntime, blockMacroProcessor.getClass());
+ asciidoctorModule.block_macro(
+ blockMacroProcessor,
+ RubyUtils.toSymbol(rubyRuntime, blockMacroProcessor.getName()), groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup inlineMacro(final InlineMacroProcessor inlineMacroProcessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ javaImport(rubyRuntime, inlineMacroProcessor.getClass());
+
+ asciidoctorModule.inline_macro(
+ inlineMacroProcessor,
+ RubyUtils.toSymbol(rubyRuntime, inlineMacroProcessor.getName()), groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup inlineMacro(final String blockName, final Class<? extends InlineMacroProcessor> inlineMacroProcessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ javaImport(rubyRuntime, inlineMacroProcessor);
+
+ asciidoctorModule.inline_macro(
+ RubyUtils.toRubyClass(rubyRuntime, inlineMacroProcessor),
+ RubyUtils.toSymbol(rubyRuntime, blockName), groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup inlineMacro(final String blockName, final String inlineMacroProcessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ javaImport(rubyRuntime, inlineMacroProcessor);
+
+ asciidoctorModule.inline_macro(
+ getClassName(inlineMacroProcessor),
+ RubyUtils.toSymbol(rubyRuntime, blockName), groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup requireRubyLibrary(final String requiredLibrary) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ RubyUtils.requireLibrary(rubyRuntime, requiredLibrary);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup loadRubyClass(final InputStream rubyClassStream) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ RubyUtils.loadRubyClass(rubyRuntime, rubyClassStream);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup rubyPreprocessor(final String preprocessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ asciidoctorModule.preprocessor(preprocessor, groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup rubyPostprocessor(final String postprocessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ asciidoctorModule.postprocessor(postprocessor, groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup rubyDocinfoProcessor(final String docinfoProcessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ asciidoctorModule.docinfo_processor(docinfoProcessor, groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup rubyIncludeProcessor(final String includeProcessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ asciidoctorModule.include_processor(includeProcessor, groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup rubyTreeprocessor(final String treeProcessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ asciidoctorModule.treeprocessor(treeProcessor, groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup rubyBlock(final String blockName, final String blockProcessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ asciidoctorModule.block_processor(
+ blockProcessor, RubyUtils.toSymbol(rubyRuntime, blockName), groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup rubyBlockMacro(final String blockName, final String blockMacroProcessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ asciidoctorModule.block_macro(
+ blockMacroProcessor, RubyUtils.toSymbol(rubyRuntime, blockName), groupName);
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public ExtensionGroup rubyInlineMacro(final String blockName, final String inlineMacroProcessor) {
+ registrations.add(new Runnable() {
+ @Override
+ public void run() {
+ asciidoctorModule.inline_macro(
+ inlineMacroProcessor, RubyUtils.toSymbol(rubyRuntime, blockName), groupName);
+ }
+ });
+ return this;
+ }
+
+ private void javaImport(Ruby ruby, Class<?> clazz) {
+ ruby.evalScriptlet(String.format("java_import '%s'", getImportLine(clazz)));
+ }
+
+ private void javaImport(Ruby ruby, String className) {
+ ruby.evalScriptlet(String.format("java_import '%s'", className));
+ }
+
+ private String getImportLine(Class<?> extensionClass) {
+ int dollarPosition = -1;
+ String className = extensionClass.getName();
+ if ((dollarPosition = className.indexOf("$")) != -1) {
+ className = className.substring(0, dollarPosition);
+ }
+ return className;
+ }
+
+ private String getClassName(String clazz) {
+ return clazz.substring(clazz.lastIndexOf(".")+1);
+ }
+
+}

MODIFY
asciidoctorj-core/src/main/java/org/asciidoctor/internal/JRubyAsciidoctor.java
asciidoctorj-core/src/main/java/org/asciidoctor/internal/JRubyAsciidoctor.java
@@ -14,6 +14,7 @@ import org.asciidoctor.ast.StructuredDocument;
import org.asciidoctor.ast.Title;
import org.asciidoctor.converter.JavaConverterRegistry;
import org.asciidoctor.converter.internal.ConverterRegistryExecutor;
+import org.asciidoctor.extension.ExtensionGroup;
import org.asciidoctor.extension.JavaExtensionRegistry;
import org.asciidoctor.extension.RubyExtensionRegistry;
import org.asciidoctor.extension.internal.ExtensionRegistryExecutor;
@@ -37,6 +38,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.UUID;
import java.util.logging.Logger;
public class JRubyAsciidoctor implements Asciidoctor {
@@ -599,6 +601,23 @@ public class JRubyAsciidoctor implements Asciidoctor {
public Document loadFile(File file, Map<String, Object> options) {
RubyHash rubyHash = RubyHashUtil.convertMapToRubyHashWithSymbols(rubyRuntime, options);
return new Document(this.asciidoctorModule.load_file(file.getAbsolutePath(), rubyHash), this.rubyRuntime);
+ }
+
+ Ruby getRubyRuntime() {
+ return this.rubyRuntime;
+ }
+
+ AsciidoctorModule getAsciidoctorModule() {
+ return asciidoctorModule;
+ }
+ @Override
+ public ExtensionGroup createGroup() {
+ return new ExtensionGroupImpl(UUID.randomUUID().toString(), this);
+ }
+
+ @Override
+ public ExtensionGroup createGroup(String groupName) {
+ return new ExtensionGroupImpl(groupName, this);
}
}

MODIFY
asciidoctorj-core/src/main/resources/org/asciidoctor/internal/asciidoctorclass.rb
asciidoctorj-core/src/main/resources/org/asciidoctor/internal/asciidoctorclass.rb
@@ -4,7 +4,7 @@ module AsciidoctorJ
include_package 'org.asciidoctor.extension'
# Treeprocessor was renamed in to TreeProcessor in https://github.com/asciidoctor/asciidoctor/commit/f1dd816ade9db457b899581841e4cf7b788aa26d
# This is necessary to run against both Asciidoctor 1.5.5 and 1.5.6
- TreeProcessor = Treeprocessor
+ TreeProcessor = Treeprocessor unless defined? TreeProcessor
end
end
@@ -19,50 +19,54 @@ class AsciidoctorModule
Asciidoctor::Extensions.unregister_all
end
- def docinfo_processor(extensionName)
- Asciidoctor::Extensions.register do
+ def unregister_extension name
+ Asciidoctor::Extensions.unregister name
+ end
+
+ def docinfo_processor(extensionName, groupName = nil)
+ Asciidoctor::Extensions.register groupName do
docinfo_processor extensionName
end
end
- def treeprocessor(extensionName)
- Asciidoctor::Extensions.register do
+ def treeprocessor(extensionName, groupName = nil)
+ Asciidoctor::Extensions.register groupName do
treeprocessor extensionName
end
end
- def include_processor(extensionName)
- Asciidoctor::Extensions.register do
+ def include_processor(extensionName, groupName = nil)
+ Asciidoctor::Extensions.register groupName do
include_processor extensionName
end
end
- def preprocessor(extensionName)
- Asciidoctor::Extensions.register do
+ def preprocessor(extensionName, groupName = nil)
+ Asciidoctor::Extensions.register groupName do
preprocessor extensionName
end
end
- def postprocessor(extensionName)
- Asciidoctor::Extensions.register do
+ def postprocessor(extensionName, groupName = nil)
+ Asciidoctor::Extensions.register groupName do
postprocessor extensionName
end
end
- def block_processor(extensionName, blockSymbol)
- Asciidoctor::Extensions.register do
+ def block_processor(extensionName, blockSymbol, groupName = nil)
+ Asciidoctor::Extensions.register groupName do
block extensionName, blockSymbol
end
end
- def block_macro(extensionName, blockSymbol)
- Asciidoctor::Extensions.register do
+ def block_macro(extensionName, blockSymbol, groupName = nil)
+ Asciidoctor::Extensions.register groupName do
block_macro extensionName, blockSymbol
end
end
- def inline_macro(extensionName, blockSymbol)
- Asciidoctor::Extensions.register do
+ def inline_macro(extensionName, blockSymbol, groupName = nil)
+ Asciidoctor::Extensions.register groupName do
inline_macro extensionName, blockSymbol
end
end

MODIFY
asciidoctorj-core/src/test/java/org/asciidoctor/extension/WhenJavaExtensionIsRegistered.java
asciidoctorj-core/src/test/java/org/asciidoctor/extension/WhenJavaExtensionIsRegistered.java
package org.asciidoctor.extension;
-import static org.asciidoctor.OptionsBuilder.options;
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.not;
-import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.hamcrest.CoreMatchers.startsWith;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
-
import org.asciidoctor.Asciidoctor;
import org.asciidoctor.AttributesBuilder;
import org.asciidoctor.Options;
@@ -37,6 +16,28 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import static org.asciidoctor.OptionsBuilder.options;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.CoreMatchers.startsWith;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
public class WhenJavaExtensionIsRegistered {
@Rule
@@ -700,4 +701,99 @@ public class WhenJavaExtensionIsRegistered {
}
+ @Test
+ public void should_unregister_postprocessor() throws IOException {
+
+ // Given: A registered Postprocessor
+ ExtensionGroup extensionGroup = asciidoctor.createGroup(UUID.randomUUID().toString())
+ .postprocessor(CustomFooterPostProcessor.class);
+
+ // When: I render a document without registering the ExtensionGroup
+ {
+ Options options = options().inPlace(false).toFile(new File(testFolder.getRoot(), "rendersample.html"))
+ .safe(SafeMode.UNSAFE).get();
+
+ asciidoctor.renderFile(classpath.getResource("rendersample.asciidoc"), options);
+
+ // Then: it is invoked
+ File renderedFile = new File(testFolder.getRoot(), "rendersample.html");
+ org.jsoup.nodes.Document doc = Jsoup.parse(renderedFile, "UTF-8");
+ Element footer = doc.getElementById("footer-text");
+ assertThat(footer.text(), not(containsString("Copyright Acme, Inc.")));
+ }
+
+ // When: I register the ExtensionGroup and render a document
+ {
+ extensionGroup.register();
+ Options options = options().inPlace(false).toFile(new File(testFolder.getRoot(), "rendersample.html"))
+ .safe(SafeMode.UNSAFE).get();
+
+ asciidoctor.renderFile(classpath.getResource("rendersample.asciidoc"), options);
+
+ // Then: it is invoked
+ File renderedFile = new File(testFolder.getRoot(), "rendersample.html");
+ org.jsoup.nodes.Document doc = Jsoup.parse(renderedFile, "UTF-8");
+ Element footer = doc.getElementById("footer-text");
+ assertThat(footer.text(), containsString("Copyright Acme, Inc."));
+ }
+ // When: I unregister the Postprocessor and render again with the same Asciidoctor instance
+ {
+ extensionGroup.unregister();;
+
+ Options options2 = options().inPlace(false).toFile(new File(testFolder.getRoot(), "rendersample2.html"))
+ .safe(SafeMode.UNSAFE).get();
+ asciidoctor.renderFile(classpath.getResource("rendersample.asciidoc"), options2);
+ File renderedFile2 = new File(testFolder.getRoot(), "rendersample2.html");
+ org.jsoup.nodes.Document doc2 = Jsoup.parse(renderedFile2, "UTF-8");
+
+ Element footer2 = doc2.getElementById("footer-text");
+ assertThat(footer2.text(), not(containsString("Copyright Acme, Inc.")));
+ }
+ }
+
+ @Test
+ public void should_unregister_block_processor()
+ throws IOException {
+
+ Map<String, Object> config = new HashMap<String, Object>();
+ config.put("contexts", Arrays.asList(":paragraph"));
+ config.put("content_model", ":simple");
+ YellBlock yellBlock = new YellBlock("yell", config);
+
+ ExtensionGroup extensionGroup = this.asciidoctor.createGroup().block(yellBlock);
+
+ {
+ String contentWithoutBlock = asciidoctor.renderFile(
+ classpath.getResource("sample-with-yell-block.ad"),
+ options().toFile(false).get());
+ Document docWithoutBlock = Jsoup.parse(contentWithoutBlock, "UTF-8");
+ Elements elementsWithoutBlock = docWithoutBlock.getElementsByClass("paragraph");
+ assertThat(elementsWithoutBlock.size(), is(1));
+ assertThat(elementsWithoutBlock.get(0).text(), not(is("THE TIME IS NOW. GET A MOVE ON.")));
+ }
+
+ {
+ extensionGroup.register();
+ String content = asciidoctor.renderFile(
+ classpath.getResource("sample-with-yell-block.ad"),
+ options().toFile(false).get());
+ Document doc = Jsoup.parse(content, "UTF-8");
+ Elements elements = doc.getElementsByClass("paragraph");
+ assertThat(elements.size(), is(1));
+ assertThat(elements.get(0).text(), is("THE TIME IS NOW. GET A MOVE ON."));
+ }
+
+ {
+ extensionGroup.unregister();
+ String contentWithoutBlock = asciidoctor.renderFile(
+ classpath.getResource("sample-with-yell-block.ad"),
+ options().toFile(false).get());
+ Document docWithoutBlock = Jsoup.parse(contentWithoutBlock, "UTF-8");
+ Elements elementsWithoutBlock = docWithoutBlock.getElementsByClass("paragraph");
+ assertThat(elementsWithoutBlock.size(), is(1));
+ assertThat(elementsWithoutBlock.get(0).text(), not(is("THE TIME IS NOW. GET A MOVE ON.")));
+ }
+ }
+
+
}

MODIFY
asciidoctorj-core/src/test/java/org/asciidoctor/extension/WhenRubyExtensionIsRegistered.java
asciidoctorj-core/src/test/java/org/asciidoctor/extension/WhenRubyExtensionIsRegistered.java
package org.asciidoctor.extension;
-import static org.asciidoctor.OptionsBuilder.options;
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-
import org.asciidoctor.Asciidoctor;
import org.asciidoctor.internal.JRubyAsciidoctor;
import org.asciidoctor.util.ClasspathResources;
@@ -13,6 +9,11 @@ import org.jsoup.select.Elements;
import org.junit.Rule;
import org.junit.Test;
+import static org.asciidoctor.OptionsBuilder.options;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assert.assertThat;
+
public class WhenRubyExtensionIsRegistered {
@Rule
@@ -37,4 +38,46 @@ public class WhenRubyExtensionIsRegistered {
}
+ @Test
+ public void ruby_extension_should_be_unregistered() {
+
+ ExtensionGroup extensionGroup = this.asciidoctor.createGroup()
+ .loadRubyClass(Class.class.getResourceAsStream("/YellRubyBlock.rb"))
+ .rubyBlock("rubyyell", "YellRubyBlock");
+
+ {
+ String contentWithoutBlock = asciidoctor.renderFile(
+ classpath.getResource("sample-with-ruby-yell-block.ad"),
+ options().toFile(false).get());
+
+ Document docWithoutBlock = Jsoup.parse(contentWithoutBlock, "UTF-8");
+ Elements elementsWithoutBlock = docWithoutBlock.getElementsByClass("paragraph");
+ assertThat(elementsWithoutBlock.size(), is(2));
+ assertThat(elementsWithoutBlock.get(1).text(), not(is("THE TIME IS NOW! GET A MOVE ON!")));
+ }
+ {
+ extensionGroup.register();
+ String content = asciidoctor.renderFile(
+ classpath.getResource("sample-with-ruby-yell-block.ad"),
+ options().toFile(false).get());
+
+ Document doc = Jsoup.parse(content, "UTF-8");
+ Elements elements = doc.getElementsByClass("paragraph");
+ assertThat(elements.size(), is(2));
+ assertThat(elements.get(1).text(), is("THE TIME IS NOW! GET A MOVE ON!"));
+ }
+ {
+ extensionGroup.unregister();
+
+ String contentWithoutBlock = asciidoctor.renderFile(
+ classpath.getResource("sample-with-ruby-yell-block.ad"),
+ options().toFile(false).get());
+
+ Document docWithoutBlock = Jsoup.parse(contentWithoutBlock, "UTF-8");
+ Elements elementsWithoutBlock = docWithoutBlock.getElementsByClass("paragraph");
+ assertThat(elementsWithoutBlock.size(), is(2));
+ assertThat(elementsWithoutBlock.get(1).text(), not(is("THE TIME IS NOW! GET A MOVE ON!")));
+ }
+ }
+
}

Fixes #359. Explicit unregistration of extensions.