Fix BlockMacro registration
MODIFY
asciidoctorj-core/src/main/java/org/asciidoctor/extension/JavaExtensionRegistry.java
asciidoctorj-core/src/main/java/org/asciidoctor/extension/JavaExtensionRegistry.java
@@ -60,6 +60,9 @@ public interface JavaExtensionRegistry {
JavaExtensionRegistry blockMacro(BlockMacroProcessor blockMacroProcessor);
+ JavaExtensionRegistry blockMacro(String blockName,
+ BlockMacroProcessor blockMacroProcessor);
+
JavaExtensionRegistry inlineMacro(InlineMacroProcessor inlineMacroProcessor);
JavaExtensionRegistry inlineMacro(String blockName,

MODIFY
asciidoctorj-core/src/main/java/org/asciidoctor/extension/processorproxies/BlockMacroProcessorProxy.java
asciidoctorj-core/src/main/java/org/asciidoctor/extension/processorproxies/BlockMacroProcessorProxy.java
@@ -61,6 +61,8 @@ public class BlockMacroProcessorProxy extends AbstractMacroProcessorProxy<BlockM
@JRubyMethod(name = "initialize", required = 1, optional = 1)
public IRubyObject initialize(ThreadContext context, IRubyObject[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
+ String macroName = RubyUtils.rubyToJava(getRuntime(), args[0], String.class);
+
if (getProcessor() != null) {
// Instance was created in Java and has options set, so we pass these
// instead of those passed by asciidoctor
@@ -73,16 +75,24 @@ public class BlockMacroProcessorProxy extends AbstractMacroProcessorProxy<BlockM
JavaEmbedUtils.javaToRuby(getRuntime(), getProcessor().getName()),
RubyHashUtil.convertMapToRubyHashWithSymbols(getRuntime(), getProcessor().getConfig())},
Block.NULL_BLOCK);
+
+ if (macroName != null) {
+ getProcessor().setName(macroName);
+ } else if (getProcessor().getName() == null) {
+ RubyHash config = (RubyHash) this.callMethod(context, "config");
+ Object rubyName = config.get(context.getRuntime().newSymbol("name"));
+ if (rubyName != null) {
+ getProcessor().setName(rubyName.toString());
+ }
+ }
+
// The extension config in the Java extension is just a view on the @config member of the Ruby part
getProcessor().updateConfig(new RubyHashMapDecorator((RubyHash)getInstanceVariable(MEMBER_NAME_CONFIG)));
} else {
// First create only the instance passing in the name
- String macroName = RubyUtils.rubyToJava(getRuntime(), args[0], String.class);
setProcessor(instantiateProcessor(macroName, new HashMap<String, Object>()));
- if (getProcessor().getName() == null) {
getProcessor().setName(macroName);
- }
// Then create the config hash that may contain config options defined in the Java constructor
RubyHash config = RubyHashUtil.convertMapToRubyHashWithSymbols(context.getRuntime(), getProcessor().getConfig());

MODIFY
asciidoctorj-core/src/main/java/org/asciidoctor/internal/JavaExtensionRegistryImpl.java
asciidoctorj-core/src/main/java/org/asciidoctor/internal/JavaExtensionRegistryImpl.java
@@ -235,7 +235,14 @@ public class JavaExtensionRegistryImpl implements JavaExtensionRegistry {
@Override
public JavaExtensionRegistry blockMacro(BlockMacroProcessor blockMacroProcessor) {
RubyClass rubyClass = BlockMacroProcessorProxy.register(rubyRuntime, blockMacroProcessor);
- getAsciidoctorModule().callMethod("block_macro", rubyClass, rubyRuntime.newString(blockMacroProcessor.getName()));
+ getAsciidoctorModule().callMethod("block_macro", rubyClass);
+ return this;
+ }
+
+ @Override
+ public JavaExtensionRegistry blockMacro(String macroName, BlockMacroProcessor blockMacroProcessor) {
+ RubyClass rubyClass = BlockMacroProcessorProxy.register(rubyRuntime, blockMacroProcessor);
+ getAsciidoctorModule().callMethod("block_macro", rubyClass, rubyRuntime.newString(macroName));
return this;
}

ADD
asciidoctorj-core/src/test/java/org/asciidoctor/extension/BlockMacroRegistrationTest.java
+package org.asciidoctor.extension;
+
+import org.asciidoctor.Asciidoctor;
+import org.asciidoctor.OptionsBuilder;
+import org.asciidoctor.ast.StructuralNode;
+import org.asciidoctor.internal.AsciidoctorCoreException;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jsoup.Jsoup;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+import java.util.Map;
+
+import static java.util.stream.Collectors.joining;
+import static java.util.stream.Collectors.toList;
+import static org.junit.Assert.assertEquals;
+
+@RunWith(Arquillian.class)
+public class BlockMacroRegistrationTest {
+
+ @ArquillianResource
+ private Asciidoctor asciidoctor;
+
+ private String document(String blockName, String text) {
+ return "= Test\n" +
+ "\n" +
+ "== A section\n" +
+ "\n" +
+ blockName + "::" + text + "[]";
+ }
+
+ public static class AbstractTestProcessor extends BlockMacroProcessor {
+ @Override
+ public Object process(StructuralNode parent, String target, Map<String, Object> attributes) {
+ return createBlock(parent, "paragraph", target.toUpperCase());
+ }
+ }
+
+ public static class TestProcessorWithName extends BlockMacroProcessor {
+
+ public static final String NAME = "somename";
+
+ public TestProcessorWithName() {
+ super(NAME);
+ }
+
+ @Override
+ public Object process(StructuralNode parent, String target, Map<String, Object> attributes) {
+ return createBlock(parent, "paragraph", target.toUpperCase());
+ }
+ }
+
+ @Name(AnnotatedTestProcessor.NAME)
+ public static class AnnotatedTestProcessor extends AbstractTestProcessor {
+ public static final String NAME = "annotated";
+ }
+
+ @Test
+ public void testRegisterNamedClassAsClass() {
+ asciidoctor.javaExtensionRegistry().blockMacro(AnnotatedTestProcessor.class);
+ final String result = asciidoctor.convert(document(AnnotatedTestProcessor.NAME, "Hello World"), OptionsBuilder.options());
+ check("HELLO WORLD", result);
+ }
+
+ @Test
+ public void testRegisterNamedClassAsClassWithExplicitName() {
+ final String explicitblockname = "explicitblockname";
+ asciidoctor.javaExtensionRegistry().blockMacro(explicitblockname, AnnotatedTestProcessor.class);
+ final String result = asciidoctor.convert(document(explicitblockname, "Hello Explicit"), OptionsBuilder.options());
+ check("HELLO EXPLICIT", result);
+ }
+ @Test
+ public void testRegisterNamedClassAsInstance() {
+ asciidoctor.javaExtensionRegistry().blockMacro(new AnnotatedTestProcessor());
+ final String result = asciidoctor.convert(document(AnnotatedTestProcessor.NAME, "Another Test"), OptionsBuilder.options());
+ check("ANOTHER TEST", result);
+ }
+
+ @Test
+ public void testRegisterNamedClassAsInstanceWithExplicitName() {
+ final String blockName = "somename";
+ asciidoctor.javaExtensionRegistry().blockMacro(blockName, new AnnotatedTestProcessor());
+ final String result = asciidoctor.convert(document(blockName, "Yet Another Test"), OptionsBuilder.options());
+ check("YET ANOTHER TEST", result);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testRegisterClassWithoutExplicitName() {
+ asciidoctor.javaExtensionRegistry().blockMacro(AbstractTestProcessor.class);
+ }
+
+
+ @Test
+ public void testRegisterClassAsClassWithExplicitName() {
+ final String explicitblockname = "anotherexplicitname";
+ asciidoctor.javaExtensionRegistry().blockMacro(explicitblockname, AbstractTestProcessor.class);
+ final String result = asciidoctor.convert(document(explicitblockname, "Hello Explicit Class"), OptionsBuilder.options());
+ check("HELLO EXPLICIT CLASS", result);
+ }
+
+ @Test(expected = AsciidoctorCoreException.class)
+ public void testRegisterClassAsInstance() {
+ asciidoctor.javaExtensionRegistry().blockMacro(new AbstractTestProcessor());
+ asciidoctor.convert(document("foo", "Hello Explicit Instance"), OptionsBuilder.options());
+ }
+
+ @Test
+ public void testRegisterClassAsInstanceWithExplicitName() {
+ final String explicitblockname = "aname";
+ asciidoctor.javaExtensionRegistry().blockMacro(explicitblockname, new AbstractTestProcessor());
+ final String result = asciidoctor.convert(document(explicitblockname, "Hello Explicit Instance"), OptionsBuilder.options());
+ check("HELLO EXPLICIT INSTANCE", result);
+ }
+
+
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testRegisterClassWithNameAsClass() {
+ asciidoctor.javaExtensionRegistry().blockMacro(TestProcessorWithName.class);
+ }
+
+ @Test
+ public void testRegisterClassWithNameAsClassWithExplicitName() {
+ final String explicitblockname = "explicitblockname";
+ asciidoctor.javaExtensionRegistry().blockMacro(explicitblockname, TestProcessorWithName.class);
+ final String result = asciidoctor.convert(document(explicitblockname, "Hello Explicit"), OptionsBuilder.options());
+ check("HELLO EXPLICIT", result);
+ }
+
+ @Test
+ public void testRegisterClassWithNameAsInstance() {
+ asciidoctor.javaExtensionRegistry().blockMacro(new TestProcessorWithName());
+ final String result = asciidoctor.convert(document(TestProcessorWithName.NAME, "Another Test"), OptionsBuilder.options());
+ check("ANOTHER TEST", result);
+ }
+
+ @Test
+ public void testRegisterClassWithNameAsInstanceWithExplicitName() {
+ final String blockName = "somename";
+ asciidoctor.javaExtensionRegistry().blockMacro(blockName, new TestProcessorWithName());
+ final String result = asciidoctor.convert(document(blockName, "Yet Another Test"), OptionsBuilder.options());
+ check("YET ANOTHER TEST", result);
+ }
+
+ private void check(String expected, String html) {
+ assertEquals(expected, Jsoup.parse(html).select("div.paragraph > p").first().text());
+ }
+}

Fix BlockMacro registration