Skip to content

Commit

Permalink
Merge pull request #1171 from abelsromero/issue-1166-retrieve-all-ima…
Browse files Browse the repository at this point in the history
…ges-in-catalog-during-conversion

Retrieve all images in catalog during conversion
  • Loading branch information
robertpanzer authored Apr 15, 2023
2 parents 0240f02 + 5086248 commit 52881e6
Show file tree
Hide file tree
Showing 15 changed files with 523 additions and 83 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ Improvement::
* Add required `--add-opens` to cli launch script to remove Jdk warnings (#1155) (@abelsromero)
* Rename deprecated `headerFooter` option to the new `standalone` with same functionality (#1155) (@abelsromero)
* Remove class `AsciidoctorUtils` to remove complexity and unused logging (#1169) (@abelsromero)
* Expose ImageReferences in the catalog (#1166) (@abelsromero)
* Return Document AST when using convert or convertFile with appropriate options (#1171) (@abelsromero)

Bug Fixes::

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ public interface Catalog {
*/
List<Footnote> getFootnotes();

/**
* Retrieves the images from the source document.
* Note that inline images are only available after `Document.getContent()` has been called.
*
* @return images occurring in document.
*/
List<ImageReference> getImages();

/**
* Refs is a map of asciidoctor ids to asciidoctor document elements.
*
Expand All @@ -29,4 +37,5 @@ public interface Catalog {
* @return a map of ids to elements that asciidoctor has collected from the document.
*/
Map<String, Object> getRefs();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.asciidoctor.ast;

public interface ImageReference {

String getTarget();

String getImagesdir();
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@

import org.asciidoctor.ast.Catalog;
import org.asciidoctor.ast.Footnote;
import org.asciidoctor.ast.ImageReference;
import org.asciidoctor.jruby.internal.RubyHashMapDecorator;
import org.jruby.RubyArray;
import org.jruby.RubyHash;
import org.jruby.RubyStruct;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class CatalogImpl implements Catalog {
public class CatalogImpl implements Catalog {

private final Map<String, Object> catalog;

Expand All @@ -22,17 +23,23 @@ public CatalogImpl(Map<String, Object> catalog) {

@Override
public List<Footnote> getFootnotes() {
RubyArray<?> rubyFootnotes = (RubyArray<?>) catalog.get("footnotes");
List<Footnote> footnotes = new ArrayList<>();
for (Object f : rubyFootnotes) {
footnotes.add(FootnoteImpl.getInstance((RubyStruct) f));
}
return footnotes;
return (List<Footnote>) ((RubyArray) catalog.get("footnotes"))
.stream()
.map(o -> FootnoteImpl.getInstance((RubyStruct) o))
.collect(Collectors.toUnmodifiableList());
}

@Override
public List<ImageReference> getImages() {
return (List<ImageReference>) ((RubyArray) catalog.get("images"))
.stream()
.map(o -> ImageReferenceImpl.getInstance((RubyStruct) o))
.collect(Collectors.toUnmodifiableList());
}

@Override
public Map<String, Object> getRefs() {
Map <String,Object> refs = new RubyHashMapDecorator((RubyHash) catalog.get("refs"), String.class);
Map<String, Object> refs = new RubyHashMapDecorator((RubyHash) catalog.get("refs"), String.class);
return Collections.unmodifiableMap(refs);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package org.asciidoctor.jruby.ast.impl;

import org.jruby.RubyStruct;

import org.asciidoctor.ast.Footnote;
import org.jruby.RubyStruct;
import org.jruby.javasupport.JavaEmbedUtils;

public class FootnoteImpl implements Footnote {
Expand All @@ -15,11 +14,11 @@ public class FootnoteImpl implements Footnote {
private String id;
private String text;

private static Object aref(RubyStruct s, String key) {
return JavaEmbedUtils.rubyToJava(s.aref(s.getRuntime().newString(key)));
private static Object aref(RubyStruct s, String key) {
return JavaEmbedUtils.rubyToJava(s.aref(s.getRuntime().newString(key)));
}

public static Footnote getInstance(Long index, String id, String text) {
public static Footnote getInstance(Long index, String id, String text) {
FootnoteImpl footnote = new FootnoteImpl();
footnote.index = index;
footnote.id = id;
Expand All @@ -35,11 +34,17 @@ public static Footnote getInstance(RubyStruct rubyFootnote) {
}

@Override
public Long getIndex() { return index; }
public Long getIndex() {
return index;
}

@Override
public String getId() { return id; }
public String getId() {
return id;
}

@Override
public String getText() { return text; }
public String getText() {
return text;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.asciidoctor.jruby.ast.impl;

import org.asciidoctor.ast.ImageReference;
import org.jruby.RubyStruct;
import org.jruby.javasupport.JavaEmbedUtils;

public class ImageReferenceImpl implements ImageReference {

private static final String IMAGESDIR_KEY_NAME = "imagesdir";
private static final String TARGET_KEY_NAME = "target";

private final String target;
private final String imagesdir;

private ImageReferenceImpl(String target, String imagesdir) {
this.target = target;
this.imagesdir = imagesdir;
}

static ImageReference getInstance(RubyStruct rubyFootnote) {
final String target = (String) aref(rubyFootnote, TARGET_KEY_NAME);
final String imagesdir = (String) aref(rubyFootnote, IMAGESDIR_KEY_NAME);
return new ImageReferenceImpl(target, imagesdir);
}

private static Object aref(RubyStruct s, String key) {
return JavaEmbedUtils.rubyToJava(s.aref(s.getRuntime().newString(key)));
}

@Override
public String getTarget() {
return target;
}

@Override
public String getImagesdir() {
return imagesdir;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import org.asciidoctor.extension.JavaExtensionRegistry;
import org.asciidoctor.extension.RubyExtensionRegistry;
import org.asciidoctor.jruby.AsciidoctorJRuby;
import org.asciidoctor.jruby.DirectoryWalker;
import org.asciidoctor.jruby.ast.impl.DocumentHeaderImpl;
import org.asciidoctor.jruby.ast.impl.NodeConverter;
import org.asciidoctor.jruby.converter.internal.ConverterRegistryExecutor;
Expand Down Expand Up @@ -216,10 +215,6 @@ private List<String> convertAllFiles(Map<String, Object> options, final Iterable
return asciidoctorContent;
}

private List<File> scanForAsciiDocFiles(DirectoryWalker directoryWalker) {
return directoryWalker.scan();
}

@Override
public void requireLibrary(String... library) {
requireLibraries(Arrays.asList(library));
Expand Down Expand Up @@ -307,11 +302,7 @@ public <T> T convert(String content, Map<String, Object> options, Class<T> expec

IRubyObject object = getAsciidoctorModule().callMethod("convert",
Optional.ofNullable(content).map(rubyRuntime::newString).orElse(null), rubyHash);
if (NodeConverter.NodeType.DOCUMENT_CLASS.isInstance(object)) {
// If a document is rendered to a file Asciidoctor returns the document, we return null
return null;
}
return RubyUtils.rubyToJava(rubyRuntime, object, expectedResult);
return adaptReturn(object, expectedResult);
} catch (RaiseException e) {
logger.severe(e.getException().getClass().getCanonicalName());
throw new AsciidoctorCoreException(e);
Expand Down Expand Up @@ -392,11 +383,7 @@ public <T> T convertFile(File file, Map<String, Object> options, Class<T> expect
try {
IRubyObject object = getAsciidoctorModule().callMethod("convert_file",
rubyRuntime.newString(file.getAbsolutePath()), rubyHash);
if (NodeConverter.NodeType.DOCUMENT_CLASS.isInstance(object)) {
// If a document is rendered to a file Asciidoctor returns the document, we return null
return null;
}
return RubyUtils.rubyToJava(rubyRuntime, object, expectedResult);
return adaptReturn(object, expectedResult);
} catch (RaiseException e) {
logger.severe(e.getMessage());

Expand All @@ -407,6 +394,17 @@ public <T> T convertFile(File file, Map<String, Object> options, Class<T> expect
}
}

private <T> T adaptReturn(IRubyObject object, Class<T> expectedResult) {
if (NodeConverter.NodeType.DOCUMENT_CLASS.isInstance(object)) {
if (Document.class.isAssignableFrom(expectedResult)) {
return (T) NodeConverter.createASTNode(object);
} else {
return null;
}
}
return RubyUtils.rubyToJava(rubyRuntime, object, expectedResult);
}

@Override
public String convertFile(File file, Options options) {
return convertFile(file, options, String.class);
Expand Down Expand Up @@ -472,7 +470,7 @@ public Document load(String content, Options options) {
return (Document) NodeConverter.createASTNode(getAsciidoctorModule().callMethod("load",
Optional.ofNullable(content).map(rubyRuntime::newString).orElse(null), rubyHash));
}

@Override
public Document loadFile(File file, Map<String, Object> options) {
RubyHash rubyHash = RubyHashUtil.convertMapToRubyHashWithSymbols(rubyRuntime, options);
Expand All @@ -488,7 +486,7 @@ public Document loadFile(File file, Options options) {
return (Document) NodeConverter.createASTNode(getAsciidoctorModule().callMethod("load_file",
rubyRuntime.newString(file.getAbsolutePath()), rubyHash));
}

@Override
public ExtensionGroup createGroup() {
return createGroup(UUID.randomUUID().toString());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package org.asciidoctor.jruby.internal;

import java.util.HashMap;
import java.util.Map;

import org.asciidoctor.Attributes;
import org.asciidoctor.Options;
import org.jruby.Ruby;

import java.util.Map;

public class RubyGemsPreloader {

private static final String CODERAY = "coderay";
Expand All @@ -15,18 +14,16 @@ public class RubyGemsPreloader {
private static final String PDF = "pdf";
private static final String REVEALJS = "asciidoctor-revealjs";

private static final Map<String, String> optionToRequiredGem = new HashMap<String, String>() {
{
put(Attributes.SOURCE_HIGHLIGHTER, "require 'coderay'");
put(Options.ERUBY, "require 'erubis'");
put(Options.TEMPLATE_DIRS, "require 'tilt'");
put(Attributes.DATA_URI, "require 'base64'");
put(Attributes.CACHE_URI, "require 'open-uri/cached'");
put(EPUB3, "require 'asciidoctor-epub3'");
put(PDF, "require 'asciidoctor-pdf'");
put(REVEALJS, "require 'asciidoctor-revealjs'");
}
};
private static final Map<String, String> optionToRequiredGem = Map.of(
Options.ERUBY, "require 'erubis'",
Options.TEMPLATE_DIRS, "require 'tilt'",
Attributes.CACHE_URI, "require 'open-uri/cached'",
Attributes.DATA_URI, "require 'base64'",
Attributes.SOURCE_HIGHLIGHTER, "require 'coderay'",
EPUB3, "require 'asciidoctor-epub3'",
PDF, "require 'asciidoctor-pdf'",
REVEALJS, "require 'asciidoctor-revealjs'"
);

private Ruby rubyRuntime;

Expand Down Expand Up @@ -60,16 +57,16 @@ && isOptionWithValue(attributes, Attributes.SOURCE_HIGHLIGHTER, CODERAY)) {
if (isOptionSet(options, Options.TEMPLATE_DIRS)) {
preloadLibrary(Options.TEMPLATE_DIRS);
}
if(isOptionSet(options, Options.BACKEND) && "epub3".equalsIgnoreCase((String) options.get(Options.BACKEND))) {

if (isOptionSet(options, Options.BACKEND) && "epub3".equalsIgnoreCase((String) options.get(Options.BACKEND))) {
preloadLibrary(EPUB3);
}

if(isOptionSet(options, Options.BACKEND) && "pdf".equalsIgnoreCase((String) options.get(Options.BACKEND))) {
if (isOptionSet(options, Options.BACKEND) && "pdf".equalsIgnoreCase((String) options.get(Options.BACKEND))) {
preloadLibrary(PDF);
}

if(isOptionSet(options, Options.BACKEND) && "revealjs".equalsIgnoreCase((String) options.get(Options.BACKEND))) {
if (isOptionSet(options, Options.BACKEND) && "revealjs".equalsIgnoreCase((String) options.get(Options.BACKEND))) {
preloadLibrary(REVEALJS);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.asciidoctor

import org.asciidoctor.ast.Block
import org.asciidoctor.ast.ContentNode
import org.asciidoctor.ast.StructuralNode
import org.asciidoctor.extension.BlockMacroProcessor
import spock.lang.Specification
Expand All @@ -13,25 +12,24 @@ class WhenTwoAsciidoctorInstancesAreCreated extends Specification {
private static final String TEST_STRING = 'Hello World'

def "then every Asciidoctor instance has its own extension registry"() {

given:
String document = '''= Test document
testmacro::Test[]
'''

when:
Asciidoctor asciidoctor1 = Asciidoctor.Factory.create(getClass().classLoader)
Asciidoctor asciidoctor2 = Asciidoctor.Factory.create(getClass().classLoader)
Asciidoctor asciidoctor1 = Asciidoctor.Factory.create()
Asciidoctor asciidoctor2 = Asciidoctor.Factory.create()

asciidoctor1.javaExtensionRegistry().blockMacro('testmacro', TestBlockMacroProcessor)

then:
asciidoctor1.convert(document, OptionsBuilder.options().standalone(false)).contains(TEST_STRING)
!asciidoctor2.convert(document, OptionsBuilder.options().standalone(false)).contains(TEST_STRING)
def standaloneDisabledOptions = Options.builder().standalone(false).build()
asciidoctor1.convert(document, standaloneDisabledOptions).contains(TEST_STRING)
!asciidoctor2.convert(document, standaloneDisabledOptions).contains(TEST_STRING)
}


static class TestBlockMacroProcessor extends BlockMacroProcessor {
TestBlockMacroProcessor(String macroName) {
super(macroName)
Expand Down
Loading

0 comments on commit 52881e6

Please sign in to comment.