From a2967ea062be92075d627fd90ce62643d6ae38f4 Mon Sep 17 00:00:00 2001 From: Robert Panzer Date: Sun, 17 Apr 2016 10:06:15 -0700 Subject: [PATCH] Fixes #450, Pass a RubyAttributesMapDecorator to Processors. --- .../BlockMacroProcessorProxy.java | 6 ++-- .../processorproxies/BlockProcessorProxy.java | 6 ++-- .../IncludeProcessorProxy.java | 3 +- .../InlineMacroProcessorProxy.java | 5 +-- .../internal/RubyAttributesMapDecorator.java | 8 +++++ .../internal/RubyHashMapDecorator.java | 10 ++++-- .../AttributeCheckingBlockProcessor.groovy | 15 ++++++++ .../WhenAJavaExtensionChecksAttributes.groovy | 35 +++++++++++++++++++ 8 files changed, 76 insertions(+), 12 deletions(-) create mode 100644 asciidoctorj-core/src/test/groovy/org/asciidoctor/extension/AttributeCheckingBlockProcessor.groovy create mode 100644 asciidoctorj-core/src/test/groovy/org/asciidoctor/extension/WhenAJavaExtensionChecksAttributes.groovy diff --git a/asciidoctorj-core/src/main/java/org/asciidoctor/extension/processorproxies/BlockMacroProcessorProxy.java b/asciidoctorj-core/src/main/java/org/asciidoctor/extension/processorproxies/BlockMacroProcessorProxy.java index 624c1ac7..d4d8bd89 100644 --- a/asciidoctorj-core/src/main/java/org/asciidoctor/extension/processorproxies/BlockMacroProcessorProxy.java +++ b/asciidoctorj-core/src/main/java/org/asciidoctor/extension/processorproxies/BlockMacroProcessorProxy.java @@ -1,8 +1,9 @@ package org.asciidoctor.extension.processorproxies; -import org.asciidoctor.ast.StructuralNode; import org.asciidoctor.ast.NodeConverter; +import org.asciidoctor.ast.StructuralNode; import org.asciidoctor.extension.BlockMacroProcessor; +import org.asciidoctor.internal.RubyAttributesMapDecorator; import org.asciidoctor.internal.RubyHashMapDecorator; import org.asciidoctor.internal.RubyHashUtil; import org.asciidoctor.internal.RubyUtils; @@ -19,7 +20,6 @@ import java.lang.reflect.InvocationTargetException; import java.util.HashMap; -import java.util.Map; public class BlockMacroProcessorProxy extends AbstractMacroProcessorProxy { @@ -104,7 +104,7 @@ public IRubyObject process(ThreadContext context, IRubyObject parent, IRubyObjec Object o = getProcessor().process( (StructuralNode) NodeConverter.createASTNode(parent), RubyUtils.rubyToJava(getRuntime(), target, String.class), - RubyUtils.rubyToJava(getRuntime(), attributes, Map.class)); + new RubyAttributesMapDecorator((RubyHash) attributes)); return convertProcessorResult(o); diff --git a/asciidoctorj-core/src/main/java/org/asciidoctor/extension/processorproxies/BlockProcessorProxy.java b/asciidoctorj-core/src/main/java/org/asciidoctor/extension/processorproxies/BlockProcessorProxy.java index 24ccc86d..4113bde4 100644 --- a/asciidoctorj-core/src/main/java/org/asciidoctor/extension/processorproxies/BlockProcessorProxy.java +++ b/asciidoctorj-core/src/main/java/org/asciidoctor/extension/processorproxies/BlockProcessorProxy.java @@ -1,9 +1,10 @@ package org.asciidoctor.extension.processorproxies; -import org.asciidoctor.ast.StructuralNode; import org.asciidoctor.ast.NodeConverter; +import org.asciidoctor.ast.StructuralNode; import org.asciidoctor.extension.BlockProcessor; import org.asciidoctor.extension.ReaderImpl; +import org.asciidoctor.internal.RubyAttributesMapDecorator; import org.asciidoctor.internal.RubyHashMapDecorator; import org.asciidoctor.internal.RubyHashUtil; import org.asciidoctor.internal.RubyUtils; @@ -20,7 +21,6 @@ import java.lang.reflect.InvocationTargetException; import java.util.HashMap; -import java.util.Map; public class BlockProcessorProxy extends AbstractProcessorProxy { @@ -117,7 +117,7 @@ public IRubyObject process(ThreadContext context, IRubyObject parent, IRubyObjec Object o = getProcessor().process( (StructuralNode) NodeConverter.createASTNode(parent), new ReaderImpl(reader), - RubyUtils.rubyToJava(getRuntime(), attributes, Map.class)); + new RubyAttributesMapDecorator((RubyHash) attributes)); return convertProcessorResult(o); } diff --git a/asciidoctorj-core/src/main/java/org/asciidoctor/extension/processorproxies/IncludeProcessorProxy.java b/asciidoctorj-core/src/main/java/org/asciidoctor/extension/processorproxies/IncludeProcessorProxy.java index e035a65e..99e8b724 100644 --- a/asciidoctorj-core/src/main/java/org/asciidoctor/extension/processorproxies/IncludeProcessorProxy.java +++ b/asciidoctorj-core/src/main/java/org/asciidoctor/extension/processorproxies/IncludeProcessorProxy.java @@ -5,6 +5,7 @@ import org.asciidoctor.extension.IncludeProcessor; import org.asciidoctor.extension.PreprocessorReader; import org.asciidoctor.extension.PreprocessorReaderImpl; +import org.asciidoctor.internal.RubyAttributesMapDecorator; import org.asciidoctor.internal.RubyHashMapDecorator; import org.asciidoctor.internal.RubyHashUtil; import org.asciidoctor.internal.RubyUtils; @@ -108,7 +109,7 @@ public IRubyObject process(ThreadContext context, IRubyObject[] args) { Document document = (Document) NodeConverter.createASTNode(args[0]); PreprocessorReader reader = new PreprocessorReaderImpl(args[1]); String target = RubyUtils.rubyToJava(getRuntime(), args[2], String.class); - Map attributes = RubyUtils.rubyToJava(getRuntime(), args[3], Map.class); + Map attributes = new RubyAttributesMapDecorator((RubyHash) args[3]); getProcessor().process(document, reader, target, attributes); return null; } diff --git a/asciidoctorj-core/src/main/java/org/asciidoctor/extension/processorproxies/InlineMacroProcessorProxy.java b/asciidoctorj-core/src/main/java/org/asciidoctor/extension/processorproxies/InlineMacroProcessorProxy.java index 19a64a5e..f1451d18 100644 --- a/asciidoctorj-core/src/main/java/org/asciidoctor/extension/processorproxies/InlineMacroProcessorProxy.java +++ b/asciidoctorj-core/src/main/java/org/asciidoctor/extension/processorproxies/InlineMacroProcessorProxy.java @@ -1,7 +1,9 @@ package org.asciidoctor.extension.processorproxies; import org.asciidoctor.ast.NodeConverter; +import org.asciidoctor.ast.StructuralNode; import org.asciidoctor.extension.InlineMacroProcessor; +import org.asciidoctor.internal.RubyAttributesMapDecorator; import org.asciidoctor.internal.RubyHashMapDecorator; import org.asciidoctor.internal.RubyHashUtil; import org.asciidoctor.internal.RubyUtils; @@ -18,7 +20,6 @@ import org.jruby.runtime.builtin.IRubyObject; import java.lang.reflect.InvocationTargetException; -import java.util.Map; public class InlineMacroProcessorProxy extends AbstractMacroProcessorProxy { @@ -115,7 +116,7 @@ public IRubyObject process(ThreadContext context, IRubyObject parent, IRubyObjec Object o = getProcessor().process( NodeConverter.createASTNode(parent), RubyUtils.rubyToJava(getRuntime(), target, String.class), - RubyUtils.rubyToJava(getRuntime(), attributes, Map.class)); + new RubyAttributesMapDecorator((RubyHash) attributes)); return convertProcessorResult(o); } diff --git a/asciidoctorj-core/src/main/java/org/asciidoctor/internal/RubyAttributesMapDecorator.java b/asciidoctorj-core/src/main/java/org/asciidoctor/internal/RubyAttributesMapDecorator.java index 56ce2baa..414ea980 100644 --- a/asciidoctorj-core/src/main/java/org/asciidoctor/internal/RubyAttributesMapDecorator.java +++ b/asciidoctorj-core/src/main/java/org/asciidoctor/internal/RubyAttributesMapDecorator.java @@ -139,4 +139,12 @@ private IRubyObject convertJavaValue(Object value) { public String toString() { return createJavaMap().toString(); } + + /** + * Invoked by JRuby when the map should be copied. + * @return + */ + public Object dup() { + return new RubyHashMapDecorator((RubyHash) rubyHash.dup()); + } } \ No newline at end of file diff --git a/asciidoctorj-core/src/main/java/org/asciidoctor/internal/RubyHashMapDecorator.java b/asciidoctorj-core/src/main/java/org/asciidoctor/internal/RubyHashMapDecorator.java index 4d067092..8df50470 100644 --- a/asciidoctorj-core/src/main/java/org/asciidoctor/internal/RubyHashMapDecorator.java +++ b/asciidoctorj-core/src/main/java/org/asciidoctor/internal/RubyHashMapDecorator.java @@ -104,7 +104,7 @@ private Map createJavaMap() { Map copy = new HashMap(); Set> rubyEntrySet = rubyHash.entrySet(); for (Map.Entry o: rubyEntrySet) { - String key; + String key = null; Object value; Object rubyKey = o.getKey(); Object rubyValue = o.getValue(); @@ -114,11 +114,15 @@ private Map createJavaMap() { key = ((RubyString) rubyKey).asJavaString(); } else if (rubyKey instanceof String) { key = (String) rubyKey; + } else if (rubyKey instanceof Long) { + // Skip it silently, it is a positional attribute } else { throw new IllegalStateException("Did not expect key " + rubyKey + " of type " + rubyKey.getClass()); } - value = convertRubyValue(rubyValue); - copy.put(key, value); + if (key != null) { + value = convertRubyValue(rubyValue); + copy.put(key, value); + } } return copy; } diff --git a/asciidoctorj-core/src/test/groovy/org/asciidoctor/extension/AttributeCheckingBlockProcessor.groovy b/asciidoctorj-core/src/test/groovy/org/asciidoctor/extension/AttributeCheckingBlockProcessor.groovy new file mode 100644 index 00000000..8bd96004 --- /dev/null +++ b/asciidoctorj-core/src/test/groovy/org/asciidoctor/extension/AttributeCheckingBlockProcessor.groovy @@ -0,0 +1,15 @@ +package org.asciidoctor.extension + +import org.asciidoctor.ast.StructuralNode + +@Contexts([Contexts.CONTEXT_PARAGRAPH]) +@Name('checkattributes') +class AttributeCheckingBlockProcessor extends BlockProcessor { + + + @Override + Object process(StructuralNode parent, Reader reader, Map attributes) { + attributes.keySet().each { assert it in String } + parent + } +} diff --git a/asciidoctorj-core/src/test/groovy/org/asciidoctor/extension/WhenAJavaExtensionChecksAttributes.groovy b/asciidoctorj-core/src/test/groovy/org/asciidoctor/extension/WhenAJavaExtensionChecksAttributes.groovy new file mode 100644 index 00000000..5a0a1b83 --- /dev/null +++ b/asciidoctorj-core/src/test/groovy/org/asciidoctor/extension/WhenAJavaExtensionChecksAttributes.groovy @@ -0,0 +1,35 @@ +package org.asciidoctor.extension + +import org.asciidoctor.Asciidoctor +import org.asciidoctor.OptionsBuilder +import org.asciidoctor.SafeMode +import org.jboss.arquillian.spock.ArquillianSputnik +import org.jboss.arquillian.test.api.ArquillianResource +import org.junit.runner.RunWith +import spock.lang.Issue +import spock.lang.Specification + +@Issue('https://github.com/asciidoctor/asciidoctorj/issues/450') +@RunWith(ArquillianSputnik) +class WhenAJavaExtensionChecksAttributes extends Specification { + + + private static final String DOCUMENT = '''= Test document + +[checkattributes,avalue] +Check me + +''' + + @ArquillianResource + private Asciidoctor asciidoctor + + def "a BlockProcessor should only get String attribute keys"() { + when: + asciidoctor.javaExtensionRegistry().block(AttributeCheckingBlockProcessor) + asciidoctor.convert(DOCUMENT, OptionsBuilder.options().headerFooter(true).safe(SafeMode.SERVER)) + + then: + noExceptionThrown() + } +}