Skip to content

Commit

Permalink
Add getImages() to Catalog
Browse files Browse the repository at this point in the history
* Current implementation works correctly when using load+getContent,
convert and convertFile.
* Fix 'convert' & 'convertFile' to correctly return Document type when applies
* Fix WhenTwoAsciidoctorInstancesAreCreated test, not being run and having invalid code
* Format RubyGemsPreloader.java and use immutable Map for options
  • Loading branch information
abelsromero committed Apr 10, 2023
1 parent 0240f02 commit 4b49877
Show file tree
Hide file tree
Showing 14 changed files with 522 additions and 78 deletions.
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 @@ -12,6 +12,7 @@
import org.asciidoctor.jruby.AsciidoctorJRuby;
import org.asciidoctor.jruby.DirectoryWalker;
import org.asciidoctor.jruby.ast.impl.DocumentHeaderImpl;
import org.asciidoctor.jruby.ast.impl.DocumentImpl;
import org.asciidoctor.jruby.ast.impl.NodeConverter;
import org.asciidoctor.jruby.converter.internal.ConverterRegistryExecutor;
import org.asciidoctor.jruby.extension.internal.ExtensionRegistryExecutor;
Expand Down Expand Up @@ -307,11 +308,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 +389,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 +400,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) new DocumentImpl(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 +476,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 +492,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 4b49877

Please sign in to comment.