diff --git a/asciidoctorj-api/src/main/java/org/asciidoctor/extension/BaseProcessor.java b/asciidoctorj-api/src/main/java/org/asciidoctor/extension/BaseProcessor.java index 62540a82d..a928bccec 100644 --- a/asciidoctorj-api/src/main/java/org/asciidoctor/extension/BaseProcessor.java +++ b/asciidoctorj-api/src/main/java/org/asciidoctor/extension/BaseProcessor.java @@ -1,18 +1,7 @@ package org.asciidoctor.extension; import org.asciidoctor.Options; -import org.asciidoctor.ast.Block; -import org.asciidoctor.ast.Cell; -import org.asciidoctor.ast.Column; -import org.asciidoctor.ast.ContentNode; -import org.asciidoctor.ast.DescriptionList; -import org.asciidoctor.ast.Document; -import org.asciidoctor.ast.ListItem; -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.*; import org.asciidoctor.log.LogRecord; import java.util.HashMap; @@ -23,7 +12,7 @@ public class BaseProcessor implements Processor { - private static ProcessorFactory processorFactory; + private static final ProcessorFactory processorFactory; static { Iterator iterator = ServiceLoader.load(ProcessorFactory.class).iterator(); @@ -33,7 +22,7 @@ public class BaseProcessor implements Processor { processorFactory = iterator.next(); } - private Processor delegate; + private final Processor delegate; public BaseProcessor() { this(new HashMap<>()); @@ -154,6 +143,41 @@ public void parseContent(StructuralNode parent, List lines) { delegate.parseContent(parent, lines); } + @Override + public Cursor newCursor(String file) { + return delegate.newCursor(file); + } + + @Override + public Cursor newCursor(String file, String dir) { + return delegate.newCursor(file, dir); + } + + @Override + public Cursor newCursor(String file, String dir, int lineno) { + return delegate.newCursor(file, dir, lineno); + } + + @Override + public Reader newReader(List source, Cursor cursor, Map options) { + return delegate.newReader(source, cursor, options); + } + + @Override + public Reader newReader(List source, Cursor cursor) { + return delegate.newReader(source, cursor); + } + + @Override + public Reader newReader(List source, Map options) { + return delegate.newReader(source, options); + } + + @Override + public Reader newReader(List source) { + return delegate.newReader(source); + } + // REMIND: Could be default method but Groovy (with compileStatic does not resolve default methods) @Override diff --git a/asciidoctorj-api/src/main/java/org/asciidoctor/extension/Preprocessor.java b/asciidoctorj-api/src/main/java/org/asciidoctor/extension/Preprocessor.java index df728f3ac..55522d7b7 100644 --- a/asciidoctorj-api/src/main/java/org/asciidoctor/extension/Preprocessor.java +++ b/asciidoctorj-api/src/main/java/org/asciidoctor/extension/Preprocessor.java @@ -15,6 +15,6 @@ public Preprocessor(Map config) { super(config); } - public abstract void process(Document document, PreprocessorReader reader); + public abstract Reader process(Document document, PreprocessorReader reader); } diff --git a/asciidoctorj-api/src/main/java/org/asciidoctor/extension/Processor.java b/asciidoctorj-api/src/main/java/org/asciidoctor/extension/Processor.java index 129b9ef33..5d0f88e37 100644 --- a/asciidoctorj-api/src/main/java/org/asciidoctor/extension/Processor.java +++ b/asciidoctorj-api/src/main/java/org/asciidoctor/extension/Processor.java @@ -1,16 +1,6 @@ package org.asciidoctor.extension; -import org.asciidoctor.ast.Block; -import org.asciidoctor.ast.Cell; -import org.asciidoctor.ast.Column; -import org.asciidoctor.ast.ContentNode; -import org.asciidoctor.ast.Document; -import org.asciidoctor.ast.ListItem; -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.*; import org.asciidoctor.log.LogRecord; import java.util.List; @@ -144,6 +134,20 @@ public interface Processor { */ void parseContent(StructuralNode parent, List lines); + Cursor newCursor(String file); + + Cursor newCursor(String file, String dir); + + Cursor newCursor(String file, String dir, int lineno); + + Reader newReader(List source, Cursor cursor, Map options); + + Reader newReader(List source, Cursor cursor); + + Reader newReader(List source, Map options); + + Reader newReader(List source); + Map getConfig(); void log(LogRecord logRecord); diff --git a/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/extension/internal/JRubyProcessor.java b/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/extension/internal/JRubyProcessor.java index 11a34a4a7..9ebe48f91 100644 --- a/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/extension/internal/JRubyProcessor.java +++ b/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/extension/internal/JRubyProcessor.java @@ -1,39 +1,13 @@ package org.asciidoctor.jruby.extension.internal; import org.asciidoctor.Options; -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.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.*; import org.asciidoctor.extension.Processor; import org.asciidoctor.extension.Reader; -import org.asciidoctor.jruby.ast.impl.ColumnImpl; -import org.asciidoctor.jruby.ast.impl.ContentNodeImpl; -import org.asciidoctor.jruby.ast.impl.DescriptionListImpl; -import org.asciidoctor.jruby.ast.impl.DocumentImpl; -import org.asciidoctor.jruby.ast.impl.ListImpl; -import org.asciidoctor.jruby.ast.impl.NodeConverter; -import org.asciidoctor.jruby.ast.impl.RowImpl; -import org.asciidoctor.jruby.ast.impl.StructuralNodeImpl; -import org.asciidoctor.jruby.internal.JRubyAsciidoctor; -import org.asciidoctor.jruby.internal.JRubyRuntimeContext; -import org.asciidoctor.jruby.internal.RubyHashUtil; -import org.asciidoctor.jruby.internal.RubyObjectWrapper; -import org.asciidoctor.jruby.internal.RubyUtils; +import org.asciidoctor.jruby.ast.impl.*; +import org.asciidoctor.jruby.internal.*; import org.asciidoctor.log.LogRecord; -import org.jruby.Ruby; -import org.jruby.RubyArray; -import org.jruby.RubyFixnum; -import org.jruby.RubyHash; -import org.jruby.RubySymbol; +import org.jruby.*; import org.jruby.runtime.builtin.IRubyObject; import java.util.ArrayList; @@ -376,6 +350,60 @@ public void parseContent(StructuralNode parent, List lines) { } } + public Cursor newCursor(String file) { + return newCursor(file, null); + } + + public Cursor newCursor(String file, String dir) { + return newCursor(file, dir, 1); + } + + public Cursor newCursor(String file, String dir, int lineNo) { + Ruby runtime = JRubyRuntimeContext.get(asciidoctor); + RubyClass klazz = runtime.getModule("Asciidoctor").getClass("Reader").getClass("Cursor"); + IRubyObject rubyCursor = klazz.newInstance(runtime.getCurrentContext(), new IRubyObject[]{ + runtime.newString(file), + dir == null ? runtime.getNil() : runtime.newString(dir), + runtime.newFixnum(lineNo), + }, org.jruby.runtime.Block.NULL_BLOCK); + return new CursorImpl(rubyCursor); + } + + @Override + public Reader newReader(List source, Cursor cursor) { + return newReader(source, cursor, null); + } + + @Override + public Reader newReader(List source, Map options) { + return newReader(source, null, options); + } + + @Override + public Reader newReader(List source) { + return newReader(source, null, null); + } + + @Override + public Reader newReader(List source, Cursor cursor, Map options) { + Ruby runtime = JRubyRuntimeContext.get(asciidoctor); + RubyClass klazz = runtime.getModule("Asciidoctor").getClass("Reader"); + + RubyHash convertMapToRubyHashWithSymbols = RubyHashUtil.convertMapToRubyHashWithSymbolsIfNecessary(runtime, options); + + RubyArray data = runtime.newArray(); + for (String line : source) { + data.add(runtime.newString(line)); + } + + IRubyObject rubyReader = klazz.newInstance(runtime.getCurrentContext(), new IRubyObject[]{ + data, + cursor == null ? runtime.getNil() : ((RubyObjectWrapper) cursor).getRubyObject(), + convertMapToRubyHashWithSymbols + }, org.jruby.runtime.Block.NULL_BLOCK); + return new ReaderImpl(rubyReader); + } + private class Parser extends RubyObjectWrapper { private final Reader reader; diff --git a/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/extension/processorproxies/PreprocessorProxy.java b/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/extension/processorproxies/PreprocessorProxy.java index 8c998a0a3..37aea9cec 100644 --- a/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/extension/processorproxies/PreprocessorProxy.java +++ b/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/extension/processorproxies/PreprocessorProxy.java @@ -2,11 +2,13 @@ import org.asciidoctor.ast.Document; import org.asciidoctor.extension.Preprocessor; +import org.asciidoctor.extension.Reader; import org.asciidoctor.jruby.ast.impl.NodeConverter; import org.asciidoctor.jruby.extension.internal.PreprocessorReaderImpl; import org.asciidoctor.jruby.internal.JRubyAsciidoctor; import org.asciidoctor.jruby.internal.RubyHashMapDecorator; import org.asciidoctor.jruby.internal.RubyHashUtil; +import org.asciidoctor.jruby.internal.RubyObjectWrapper; import org.jruby.Ruby; import org.jruby.RubyClass; import org.jruby.RubyHash; @@ -91,10 +93,14 @@ public IRubyObject initialize(ThreadContext context, IRubyObject options) throws @JRubyMethod(name = "process", required = 2) public IRubyObject process(ThreadContext context, IRubyObject document, IRubyObject preprocessorReader) { - getProcessor().process( + PreprocessorReaderImpl readerArg = new PreprocessorReaderImpl(preprocessorReader); + Reader reader = getProcessor().process( (Document) NodeConverter.createASTNode(document), - new PreprocessorReaderImpl(preprocessorReader)); + readerArg); - return getRuntime().getNil(); + if (reader == null || reader == readerArg) { + return getRuntime().getNil(); + } + return ((RubyObjectWrapper) reader).getRubyObject(); } } diff --git a/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/internal/RubyHashUtil.java b/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/internal/RubyHashUtil.java index 423f45505..f0684c9a6 100644 --- a/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/internal/RubyHashUtil.java +++ b/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/internal/RubyHashUtil.java @@ -24,6 +24,10 @@ public static RubyHash convertMapToRubyHashWithSymbolsIfNecessary(Ruby rubyRunti RubyHash rubyHash = new RubyHash(rubyRuntime); + if (options == null) { + return rubyHash; + } + Set> optionsSet = options.entrySet(); for (Entry entry : optionsSet) { diff --git a/asciidoctorj-core/src/test/groovy/org/asciidoctor/extension/WhenAPreprocessorIsRegistered.groovy b/asciidoctorj-core/src/test/groovy/org/asciidoctor/extension/WhenAPreprocessorIsRegistered.groovy index cee6257c9..885be592c 100644 --- a/asciidoctorj-core/src/test/groovy/org/asciidoctor/extension/WhenAPreprocessorIsRegistered.groovy +++ b/asciidoctorj-core/src/test/groovy/org/asciidoctor/extension/WhenAPreprocessorIsRegistered.groovy @@ -32,7 +32,7 @@ $secondLine""" asciidoctor.javaExtensionRegistry().preprocessor(new Preprocessor() { @Override - void process(Document doc, PreprocessorReader reader) { + Reader process(Document doc, PreprocessorReader reader) { preprocessorCalled.set(true) assert reader.peekLine() == firstLine @@ -46,6 +46,7 @@ $secondLine""" reader.advance() assert reader.peekLine() == null + reader } }) @@ -63,7 +64,7 @@ $secondLine""" asciidoctor.javaExtensionRegistry().preprocessor(new Preprocessor() { @Override - void process(Document doc, PreprocessorReader reader) { + Reader process(Document doc, PreprocessorReader reader) { preprocessorCalled.set(true) assert reader.peekLines(ONE) == [firstLine] @@ -78,6 +79,7 @@ $secondLine""" assert reader.peekLines(ONE) == [] assert reader.peekLines(TWO) == [] + reader } }) @@ -95,12 +97,13 @@ $secondLine""" asciidoctor.javaExtensionRegistry().preprocessor(new Preprocessor() { @Override - void process(Document doc, PreprocessorReader reader) { + Reader process(Document doc, PreprocessorReader reader) { preprocessorCalled.set(true) assert reader.readLine() == firstLine assert reader.readLine() == secondLine assert reader.readLine() == null + reader } }) @@ -120,7 +123,7 @@ $secondLine""" asciidoctor.javaExtensionRegistry().preprocessor(new Preprocessor() { @Override - void process(Document doc, PreprocessorReader reader) { + Reader process(Document doc, PreprocessorReader reader) { preprocessorCalled.set(true) assert reader.peekLine() == firstLine @@ -131,6 +134,7 @@ $secondLine""" assert reader.readLine() == anotherLine assert reader.peekLine() == firstLine assert reader.readLine() == firstLine + reader } }) @@ -151,7 +155,7 @@ $secondLine""" asciidoctor.javaExtensionRegistry().preprocessor(new Preprocessor() { @Override - void process(Document doc, PreprocessorReader reader) { + Reader process(Document doc, PreprocessorReader reader) { preprocessorCalled.set(true) assert reader.peekLine() == firstLine @@ -164,6 +168,7 @@ $secondLine""" assert reader.readLine() == anotherSecondLine assert reader.peekLine() == firstLine assert reader.readLine() == firstLine + reader } }) diff --git a/asciidoctorj-core/src/test/groovy/org/asciidoctor/extension/WhenAPreprocessorSetsTheSourceMapOption.groovy b/asciidoctorj-core/src/test/groovy/org/asciidoctor/extension/WhenAPreprocessorSetsTheSourceMapOption.groovy index 2a2e4cdba..d5364f111 100644 --- a/asciidoctorj-core/src/test/groovy/org/asciidoctor/extension/WhenAPreprocessorSetsTheSourceMapOption.groovy +++ b/asciidoctorj-core/src/test/groovy/org/asciidoctor/extension/WhenAPreprocessorSetsTheSourceMapOption.groovy @@ -18,8 +18,9 @@ class WhenAPreprocessorSetsTheSourceMapOption extends Specification { static class SourceMapOptionPreprocessor extends Preprocessor { @Override - void process(Document document, PreprocessorReader reader) { + Reader process(Document document, PreprocessorReader reader) { document.sourcemap = true + reader } } diff --git a/asciidoctorj-core/src/test/java/org/asciidoctor/extension/ChangeAttributeValuePreprocessor.java b/asciidoctorj-core/src/test/java/org/asciidoctor/extension/ChangeAttributeValuePreprocessor.java index 388ca4615..7254e764d 100644 --- a/asciidoctorj-core/src/test/java/org/asciidoctor/extension/ChangeAttributeValuePreprocessor.java +++ b/asciidoctorj-core/src/test/java/org/asciidoctor/extension/ChangeAttributeValuePreprocessor.java @@ -11,10 +11,11 @@ public ChangeAttributeValuePreprocessor(Map config) { } @Override - public void process(Document document, + public Reader process(Document document, PreprocessorReader reader) { document.getAttributes().put("content", "Alex"); + return reader; } } \ No newline at end of file diff --git a/asciidoctorj-core/src/test/java/org/asciidoctor/extension/FrontMatterPreprocessor.java b/asciidoctorj-core/src/test/java/org/asciidoctor/extension/FrontMatterPreprocessor.java index c2bd6966e..19a1f27e1 100644 --- a/asciidoctorj-core/src/test/java/org/asciidoctor/extension/FrontMatterPreprocessor.java +++ b/asciidoctorj-core/src/test/java/org/asciidoctor/extension/FrontMatterPreprocessor.java @@ -8,10 +8,10 @@ public class FrontMatterPreprocessor extends Preprocessor { @Override - public void process(Document document, PreprocessorReader reader) { + public Reader process(Document document, PreprocessorReader reader) { List lines = reader.getLines(); if (lines.isEmpty()) { - return; + return reader; } List frontMatter = new ArrayList<>(); if ("---".equals(lines.get(0).trim())) { @@ -28,5 +28,6 @@ public void process(Document document, PreprocessorReader reader) { } } } + return reader; } } diff --git a/asciidoctorj-core/src/test/java/org/asciidoctor/extension/HardBreakPreprocessor.java b/asciidoctorj-core/src/test/java/org/asciidoctor/extension/HardBreakPreprocessor.java new file mode 100644 index 000000000..3695b00b2 --- /dev/null +++ b/asciidoctorj-core/src/test/java/org/asciidoctor/extension/HardBreakPreprocessor.java @@ -0,0 +1,18 @@ +package org.asciidoctor.extension; + +import org.asciidoctor.ast.Document; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class HardBreakPreprocessor extends Preprocessor { + + @Override + public Reader process(Document document, PreprocessorReader reader) { + List lines = reader.getLines(); + return newReader(lines.stream() + .map(line -> line.isEmpty() || line.startsWith("=") ? line : line + " +") + .collect(Collectors.toList())); + } +} diff --git a/asciidoctorj-core/src/test/java/org/asciidoctor/extension/HasMoreLinesPreprocessor.java b/asciidoctorj-core/src/test/java/org/asciidoctor/extension/HasMoreLinesPreprocessor.java index 7737fc739..98143d1e1 100644 --- a/asciidoctorj-core/src/test/java/org/asciidoctor/extension/HasMoreLinesPreprocessor.java +++ b/asciidoctorj-core/src/test/java/org/asciidoctor/extension/HasMoreLinesPreprocessor.java @@ -4,8 +4,8 @@ import java.util.Map; +import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; public class HasMoreLinesPreprocessor extends Preprocessor { @@ -14,10 +14,11 @@ public HasMoreLinesPreprocessor(Map config) { } @Override - public void process(Document document, + public Reader process(Document document, PreprocessorReader reader) { - assertThat(reader.hasMoreLines(), is(true)); + assertThat(reader.hasMoreLines()).isTrue(); + return reader; } } diff --git a/asciidoctorj-core/src/test/java/org/asciidoctor/extension/NextLineEmptyPreprocessor.java b/asciidoctorj-core/src/test/java/org/asciidoctor/extension/NextLineEmptyPreprocessor.java index 030ce6ae2..50a1e6f19 100644 --- a/asciidoctorj-core/src/test/java/org/asciidoctor/extension/NextLineEmptyPreprocessor.java +++ b/asciidoctorj-core/src/test/java/org/asciidoctor/extension/NextLineEmptyPreprocessor.java @@ -14,7 +14,7 @@ public NextLineEmptyPreprocessor(Map config) { } @Override - public void process(Document document, + public Reader process(Document document, PreprocessorReader reader) { assertThat(reader.isNextLineEmpty(), is(false)); @@ -22,6 +22,8 @@ public void process(Document document, reader.advance(); assertThat(reader.isNextLineEmpty(), is(true)); + + return reader; } } diff --git a/asciidoctorj-core/src/test/java/org/asciidoctor/extension/NumberLinesPreprocessor.java b/asciidoctorj-core/src/test/java/org/asciidoctor/extension/NumberLinesPreprocessor.java index a8d688524..a67b050cc 100644 --- a/asciidoctorj-core/src/test/java/org/asciidoctor/extension/NumberLinesPreprocessor.java +++ b/asciidoctorj-core/src/test/java/org/asciidoctor/extension/NumberLinesPreprocessor.java @@ -2,8 +2,8 @@ import org.asciidoctor.ast.Document; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; public class NumberLinesPreprocessor extends Preprocessor { @@ -11,7 +11,8 @@ public NumberLinesPreprocessor() { } @Override - public void process(Document document, PreprocessorReader reader) { - assertThat(reader.getLineNumber(), is(1)); + public Reader process(Document document, PreprocessorReader reader) { + assertThat(reader.getLineNumber()).isEqualTo(1); + return reader; } } diff --git a/asciidoctorj-core/src/test/java/org/asciidoctor/extension/FrontMatterPreprocessorTest.java b/asciidoctorj-core/src/test/java/org/asciidoctor/extension/PreprocessorTest.java similarity index 79% rename from asciidoctorj-core/src/test/java/org/asciidoctor/extension/FrontMatterPreprocessorTest.java rename to asciidoctorj-core/src/test/java/org/asciidoctor/extension/PreprocessorTest.java index 3e5aaa7c5..5388368d9 100644 --- a/asciidoctorj-core/src/test/java/org/asciidoctor/extension/FrontMatterPreprocessorTest.java +++ b/asciidoctorj-core/src/test/java/org/asciidoctor/extension/PreprocessorTest.java @@ -15,7 +15,7 @@ import static org.assertj.core.api.Assertions.assertThat; @RunWith(Arquillian.class) -public class FrontMatterPreprocessorTest { +public class PreprocessorTest { @ArquillianResource private Asciidoctor asciidoctor; @@ -63,4 +63,19 @@ public void shouldRemoveFrontMatter() { assertThat(body.getElementsByTag("p").first().text()) .startsWith("This is a sample page"); } + + @Test + public void shouldUseNewReader() { + // Given: the HardBreakPreprocessor + asciidoctor.javaExtensionRegistry().preprocessor(HardBreakPreprocessor.class); + + // And a document + String document = "Ruby is red.\n" + + "Java is beige."; + + // When the document is converted + String html = asciidoctor.convert(document, Options.builder().toFile(false).build()); + org.jsoup.nodes.Document htmlDoc = Jsoup.parse(html); + assertThat(htmlDoc.getElementsByTag("br")).hasSize(2); + } } diff --git a/asciidoctorj-documentation/src/test/java/org/asciidoctor/integrationguide/extension/CommentPreprocessor.java b/asciidoctorj-documentation/src/test/java/org/asciidoctor/integrationguide/extension/CommentPreprocessor.java index a474bac3e..5a5668237 100644 --- a/asciidoctorj-documentation/src/test/java/org/asciidoctor/integrationguide/extension/CommentPreprocessor.java +++ b/asciidoctorj-documentation/src/test/java/org/asciidoctor/integrationguide/extension/CommentPreprocessor.java @@ -4,6 +4,7 @@ import org.asciidoctor.ast.Document; import org.asciidoctor.extension.Preprocessor; import org.asciidoctor.extension.PreprocessorReader; +import org.asciidoctor.extension.Reader; import java.util.ArrayList; import java.util.List; @@ -11,7 +12,7 @@ public class CommentPreprocessor extends Preprocessor { // <1> @Override - public void process(Document document, PreprocessorReader reader) { + public Reader process(Document document, PreprocessorReader reader) { List lines = reader.readLines(); // <2> List newLines = new ArrayList(); @@ -31,6 +32,7 @@ public void process(Document document, PreprocessorReader reader) { } reader.restoreLines(newLines); // <4> + return reader; } } //end::include[]