AsciidoctorJ is the official library for running Asciidoctor on the JVM. Using AsciidoctorJ, you can convert AsciiDoc content or analyze the structure of a parsed AsciiDoc document from Java and other JVM languages.
AsciidoctorJ is published to Maven Central and Bintray. The artifact information can be found in the tables below.
Group Id | Artifact Id | Version | Download |
---|---|---|---|
org.asciidoctor |
pom jar javadoc (jar) sources (jar) distribution (zip tar) |
||
org.asciidoctor |
|||
org.asciidoctor |
asciidoctorj-epub3 |
1.5.0-alpha.15 |
|
org.asciidoctor |
asciidoctorj-pdf |
1.5.0-beta.8 |
Group Id | Artifact Id | Version | Download |
---|---|---|---|
org.asciidoctor |
pom jar javadoc (jar) sources (jar) distribution (zip tar) |
||
org.asciidoctor |
|||
org.asciidoctor |
asciidoctorj-epub3 |
1.5.0-alpha.15 |
|
org.asciidoctor |
asciidoctorj-pdf |
1.5.0-beta.8 |
🔥
|
The artifactId changed to asciidoctorj starting in 1.5.0.
|
If you download from a distribution link above (zip or tar), you can get started straight away from the command line.
First, expand the downloaded file. That puts everything in directory asciidoctorj-2.2.0
.
Within that directory are bin
and lib
directories. bin
contains the executables — asciidoctorj
for
Linux and macOS, and asciidoctorj.bat
for Windows. lib
contains the supporting libraries.
Verify the application runs by specifying the appropriate executable with no parameters; it should display the various run options available (i.e., help).
Linux: asciidoctorj-2.2.0/bin/asciidoctorj
Windows: asciidoctorj-2.2.0\bin\asciidoctorj.bat
Next, say you want to convert an ASCIIDOC (.adoc) file — such as this README — to a pdf.
Linux: asciidoctorj-2.2.0/bin/asciidoctorj -b pdf README.adoc
Windows: asciidoctorj-2.2.0\bin\asciidoctorj.bat -b pdf README.adoc
Boom! That should convert the README to a PDF named README.pdf. To create a PDF with a different name — say, READTHIS.pdf — just add the -o switch:
Linux: asciidoctorj-2.2.0/bin/asciidoctorj -b pdf -o READTHIS.pdf README.adoc
Windows: asciidoctorj-2.2.0\bin\asciidoctorj.bat -b pdf -o READTHIS.pdf README.adoc
The rest of the document addresses the asciidoctorj API, for doing more complex conversions from within a JVM-based application.
To start using AsciidoctorJ, you need to add the required dependency to the dependency management system of your choice, Maven, Gradle or Apache Ivy. If you don’t use a Dependency Management system please check the dependency graph and add all jars in it to your classpath.
<dependencies>
<dependency>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctorj</artifactId>
<version>2.2.0</version> <!--(1)-->
</dependency>
</dependencies>
dependencies {
compile 'org.asciidoctor:asciidoctorj:2.2.0'
}
libraryDependencies += "org.asciidoctor" % "asciidoctorj" % "2.2.0" // (1)
-
Specifying the version of AsciidoctorJ implicitly selects the version of Asciidoctor
:dependencies [[org.asciidoctor/asciidoctorj "2.2.0"]]
💡
|
In addition to using AsciidoctorJ directly, you can invoke it as part of your build using the Maven or Gradle plugin. |
📎
|
The versions of Asciidoctor and AsciidoctorJ no longer align since version 1.6.0 of AsciidoctorJ.
Please check the corresponding release notes to find out which version of Asciidoctor is packaged if you are embedding the library.
If you use the distribution you can call asciidoctorj --version to get the version of Asciidoctor that is embedded in AsciidoctorJ.
|
A Chocolatey package is available which installs the asciidoctorj-2.2.0-bin.zip Bintray artifact along with a binary shim in %ChocolateyInstall%\bin which lets you run AsciidoctorJ from the command line.
C:\> choco install asciidoctorj
C:\> where asciidoctorj
C:\ProgramData\chocolatey\bin\asciidoctorj.exe
C:\> asciidoctorj -b pdf README.adoc
The main entry point for AsciidoctorJ is the Asciidoctor
Java interface.
This interface provides four methods for converting AsciiDoc content.
-
convert
-
convertFile
-
convertFiles
-
convertDirectory
You’ll learn about these methods in the converting documents section.
❗
|
Prior to Asciidoctor 1.5.0, the term render was used in these method names instead of convert (i.e., render , renderFile , renderFiles and renderDirectory ).
AsciidoctorJ continues to support the old method names for backwards compatibility.
|
Asciidoctor
interface
Method Name | Return Type | Description |
---|---|---|
|
|
Parses AsciiDoc content read from a string or stream and converts it to the format specified by the |
|
|
Parses AsciiDoc content read from a file and converts it to the format specified by the |
|
|
Parses a collection of AsciiDoc files and converts them to the format specified by the |
|
|
Parses all AsciiDoc files found in the specified directory (using the provided strategy) and converts them to the format specified by the |
📎
|
All the methods listed in Table 3 are overloaded to accommodate various input types and options. |
You retrieve an instance of the Asciidoctor
interface from the factory method provided.
import static org.asciidoctor.Asciidoctor.Factory.create;
import org.asciidoctor.Asciidoctor;
Asciidoctor asciidoctor = create();
Once you retrieve an instance of the Asciidoctor
interface, you can use it to convert AsciiDoc content.
Here’s an example of using AsciidoctorJ to convert an AsciiDoc string.
📎
|
The following convertFile or convertFiles methods will only return a converted String object or array if you disable writing to a file, which is enabled by default.
To disable writing to a file, create a new Options object, disable the option to create a new file with option.setToFile(false) , and then pass the object as a parameter to convertFile or convertFiles .
|
//...
import java.util.HashMap;
//...
String html = asciidoctor.convert(
"Writing AsciiDoc is _easy_!",
new HashMap<String, Object>());
System.out.println(html);
The convertFile
method will convert the contents of an AsciiDoc file.
//...
import java.util.HashMap;
//...
String html = asciidoctor.convertFile(
new File("sample.adoc"),
new HashMap<String, Object>());
System.out.println(html);
The convertFiles
method will convert a collection of AsciiDoc files:
//...
import java.util.Arrays;
//...
String[] result = asciidoctor.convertFiles(
Arrays.asList(new File("sample.adoc")),
new HashMap<String, Object>());
for (String html : result) {
System.out.println(html);
}
|
If the converted content is written to files, the convertFiles method will return a String Array (i.e., String[] ) with the names of all the converted documents.
|
Another method provided by the Asciidoctor
interface is convertDirectory
.
This method converts all of the files with AsciiDoc extensions (.adoc
(preferred), .ad
, .asciidoc
, .asc
) that are present within a specified folder and following given strategy.
An instance of the DirectoryWalker
interface, which provides a strategy for locating files to process, must be passed as the first parameter of the convertDirectory
method.
Currently Asciidoctor
provides two built-in implementations of the DirectoryWalker
interface:
DirectoryWalker
implementations
Class | Description |
---|---|
|
Converts all files of given folder and all its subfolders. Ignores files starting with underscore (_). |
|
Converts all files of given folder following a glob expression. |
If the converted content is not written into files, convertDirectory
will return an array listing all the documents converted.
//...
import org.asciidoctor.AsciiDocDirectoryWalker;
//...
String[] result = asciidoctor.convertDirectory(
new AsciiDocDirectoryWalker("src/asciidoc"),
new HashMap<String, Object>());
for (String html : result) {
System.out.println(html);
}
Another way to convert AsciiDoc content is by calling the convert
method and providing a standard Java java.io.Reader
and java.io.Writer
.
The Reader
interface is used as the source, and the converted content is written to the Writer
interface.
//...
import java.io.FileReader;
import java.io.StringWriter;
//...
FileReader reader = new FileReader(new File("sample.adoc"));
StringWriter writer = new StringWriter();
asciidoctor.convert(reader, writer, options().asMap());
StringBuffer htmlBuffer = writer.getBuffer();
System.out.println(htmlBuffer.toString());
Asciidoctor provides security levels that control the read and write access of attributes, the include directive, macros, and scripts while a document is processing. Each level includes the restrictions enabled in the prior security level.
When Asciidoctor (and AsciidoctorJ) is used as API, it uses SECURE
safe mode by default.
This mode is the most restrictive one and in summary it disallows the document from attempting to read files from the file system and including their contents into the document.
We recommend you to set SAFE
safe mode when rendering AsciiDoc documents using AsciidoctorJ to have almost all Asciidoctor features such as icons, include directive or retrieving content from URIs enabled.
Safe mode is set as option when a document is rendered. For example:
import static org.asciidoctor.OptionsBuilder.options;
Map<String, Object> options = options().safe(SafeMode.SAFE)
.asMap();
String outfile = asciidoctor.convertFile(new File("sample.adoc"), options);
We are going to explain in more detail options in next section.
You can read more about safe modes in http://asciidoctor.org/docs/user-manual/#running-asciidoctor-securely
Asciidoctor supports numerous options, such as:
in_place
-
Converts the output to a file adjacent to the input file.
template_dirs
-
Specifies a directory of Tilt-compatible templates to be used instead of the default built-in templates
attributes
-
A Hash (key-value pairs) of attributes to configure various aspects of the AsciiDoc processor
The second parameter of the convert
method is java.util.Map
.
The options listed above can be set in java.util.Map
.
in_place
option and the backend
attributeMap<String, Object> attributes = new HashMap<String, Object>();
attributes.put("backend", "docbook"); // (1)
Map<String, Object> options = new HashMap<String, Object>();
options.put("attributes", attributes); // (2)
options.put("in_place", true); // (3)
String outfile = asciidoctor.convertFile(new File("sample.adoc"), options);
-
Defines the
backend
attribute asdocbook
in the attributes map -
Registers the attributes map as the
attributes
option in the options map -
Defines the
in_place
option in the options map
Another way for setting options is by using org.asciidoctor.Options
class.
Options
is a simple Java class which contains methods for setting required options.
Note that related with org.asciidoctor.Options
class, there is org.asciidoctor.Attributes
class, which can be used for setting attributes.
The convert
method is overloaded so org.asciidoctor.Options
can be passed instead of a java.util.Map
.
Attributes attributes = new Attributes();
attributes.setBackend("docbook"); // (1)
Options options = new Options();
options.setAttributes(attributes); // (2)
options.setInPlace(true); // (3)
String outfile = asciidoctor.convertFile(new File("sample.adoc"), options);
-
Defines the
backend
attribute asdocbook
in the attributes class -
Registers the attributes class as the
attributes
option in the options class -
Defines the
in_place
option in the options class
AsciidoctorJ also provides two builder classes to create these maps and classes in a more readable form.
AttributesBuilder
-
Used to define attributes with a fluent API
OptionsBuilder
-
Used to define options with a fluent API
The code below results in the same output as the previous example but uses the builder classes.
import static org.asciidoctor.AttributesBuilder.attributes;
import static org.asciidoctor.OptionsBuilder.options;
//...
Map<String, Object> attributes = attributes().backend("docbook") // (1)
.asMap();
Map<String, Object> options = options().inPlace(true)
.attributes(attributes) // (2)
.asMap(); // (3)
String outfile = asciidoctor.convertFile(new File("sample.adoc"), options);
-
Defines the
backend
attribute asdocbook
using fluent API. -
Registers the attributes map as
attributes
. -
Converts options to
java.util.Map
instance.
import static org.asciidoctor.AttributesBuilder.attributes;
import static org.asciidoctor.OptionsBuilder.options;
//...
Attributes attributes = attributes().backend("docbook").get(); // (1)
Options options = options().inPlace(true).attributes(attributes).get(); // (2)
String outfile = asciidoctor.convertFile(new File("sample.adoc"), options); // (3)
-
Defines and returns an
Attributes
class instead ofjava.util.Map
by callingget()
method instead ofasMap()
. -
Defines and returns an
Options
class instead ofjava.util.Map
by callingget()
method instead ofasMap()
. -
Converts the document passing
Options
class.
💡
|
All methods used to convert content are overloaded with OptionsBuilder parameter, so it is no longer required to call get nor asMap methods.
|
|
The icons attribute requires a String to set the value used to “draw” icons.
At this time, you can use two constants org.asciidoctor.Attributes.IMAGE_ICONS for using the same approach as AsciiDoc, that is using img tags, or org.asciidoctor.Attributes.FONT_ICONS for using icons from Font Awesome.
|
Attributes can be specified as String
or Array
instead of pair key/value by using org.asciidoctor.Attributes.setAttributes(String)
or org.asciidoctor.Attributes.setAttributes(String...)
and AttributesBuilder
methods.
//...
Attributes attributes = attributes().attributes("toc numbered").get();
Options options = options().attributes(attributes).get();
Passing attributes as a string is equivalent to passing individual attributes.
//...
Attributes attributes = attributes().tableOfContents(true).sectionNumbers(true).get();
Options options = options().attributes(attributes).get();
You can also use an array.
//...
String[] attributesArray = new String[]{"toc", "source-highlighter=coderay"};
Attributes attributes = attributes().attributes(attributesArray).sectionNumbers(true).get();
Options options = options().attributes(attributes).get();
Passing attributes as an array is equivalent to passing individual attribute.
//...
Attributes attributes = attributes().tableOfContents(true).sectionNumbers(true).sourceHighlighter("coderay").get();
Options options = options().attributes(attributes).get();
A utility class AsciiDocDirectoryWalker
is available for searching the AsciiDoc files present in a root folder and its subfolders.
AsciiDocDirectoryWalker
locates all files that end with .adoc
, .ad
, .asciidoc
or .asc
.
Also it ignores all files starting with underscore (_
).
AsciiDocDirectoryWalker
import java.util.List;
import org.asciidoctor.AsciiDocDirectoryWalker;
DirectoryWalker directoryWalker = new AsciiDocDirectoryWalker("docs"); // (1)
List<File> asciidocFiles = directoryWalker.scan(); // (2)
-
Defines which parent directory is used for searching.
-
Returns a list of all AsciiDoc files found in root folder and its subfolders.
A utility class GlobDirectoryWalker
is available for searching the AsciiDoc files present in a root folder and scanning using a Glob
expression.
GlobDirectoryWalker
locates all files that end with .adoc
, .ad
, .asciidoc
or .asc
.
GlobDirectoryWalker
import java.util.List;
import org.asciidoctor.GlobDirectoryWalker;
DirectoryWalker directoryWalker = new GlobDirectoryWalker("docs", "**/*.adoc"); // (1)
List<File> asciidocFiles = directoryWalker.scan(); // (2)
-
Defines which parent directory is used for searching and the glob expression.
-
Returns a list of all AsciiDoc files matching given glob expression.
Instead of converting an AsciiDoc document, you may want to parse the document to read information it contains or navigate the document’s structure. AsciidoctorJ let’s you do this!
AsciidoctorJ provides a model of the abstract syntax tree of the document. These objects are directly linked to the internal representation.
To load a document, use the load
or loadFile
methods.
import org.asciidoctor.ast.Document;
//...
Document document = asciidoctor.load(DOCUMENT, new HashMap<String, Object>()); // (1)
assertThat(document.doctitle(), is("Document Title")); // (2)
-
Document from a String is loaded into
Document
object. -
Title of the document is retrieved.
But also all blocks that conforms the document can be retrieved.
Currently there are support for three kinds of blocks.
Blocks
itself, Section
for sections of the document and StructuralNode
which is the base type where all kind of blocks (including those not mapped as Java class) are mapped.
import org.asciidoctor.ast.Document;
import org.asciidoctor.ast.Section;
//...
Document document = asciidoctor.load(DOCUMENT, new HashMap<String, Object>()); // (1)
Section section = (Section) document.blocks().get(1); // (2)
assertThat(section.index(), is(0)); // (3)
assertThat(section.sectname(), is("sect1"));
assertThat(section.special(), is(false));
-
Document from a String is loaded into
Document
object. -
All blocks are get and because in this example the first block is a Section block, we cast it directly.
-
Concrete methods for sections can be called.
Blocks can also be retrieved from query using findBy
method.
Document document = asciidoctor.load(DOCUMENT, new HashMap<String, Object>());
Map<Object, Object> selector = new HashMap<>(); // (1)
selector.put("context", ":image"); // (2)
List<StructuralNode> findBy = document.findBy(selector);
assertThat(findBy, hasSize(2)); //(3)
-
To make queries you need to use a
map
approach. Currently this is because of the Asciidoctor API but it will change in near future. -
In this example all blocks with context as image is returned. Notice that the colon (
:
) must be added in the value part. -
Document used as example contains two images.
📎
|
If you are migrating existing extensions to a newer version of AsciidoctorJ please read the Extension Migration Guide |
One of the major improvements to Asciidoctor recently is the extensions API. AsciidoctorJ brings this extension API to the JVM environment. AsciidoctorJ allows us to write extensions in Java instead of Ruby.
Asciidoctor provides seven types of extension points. Each extension point has an abstract class in Java that maps to the extension API in Ruby.
Name | Class |
---|---|
|
org.asciidoctor.extension.Preprocessor |
|
org.asciidoctor.extension.Treeprocessor |
|
org.asciidoctor.extension.Postprocessor |
|
org.asciidoctor.extension.BlockProcessor |
|
org.asciidoctor.extension.BlockMacroProcessor |
|
org.asciidoctor.extension.InlineMacroProcessor |
|
org.asciidoctor.extension.IncludeProcessor |
You can read more about the Extension API in the Integrator Guide.
You can even register extensions written in Ruby using AsciidoctorJ.
To register a Ruby extension you must get a RubyExtensionRegistry
class instead of JavaExtensionRegistry
.
RubyExtensionRegistry rubyExtensionRegistry = this.asciidoctor.rubyExtensionRegistry(); // (1)
rubyExtensionRegistry.loadClass(Class.class.getResourceAsStream("/YellRubyBlock.rb")).block("rubyyell", "YellRubyBlock"); // (2)
String content = asciidoctor.convertFile(new File(
"target/test-classes/sample-with-ruby-yell-block.ad"),
options().toFile(false).get());
-
rubyExtensionRegistry
method is called to get a rubyExtensionRegistry instance. -
Ruby file containing a class implementing a Block extension is loaded inside the Ruby runtime. Then the block is registered with a name (rubyyell), and we pass the name of the class to be instantiated.
require 'asciidoctor'
require 'asciidoctor/extensions'
class YellRubyBlock < Asciidoctor::Extensions::BlockProcessor
option :contexts, [:paragraph]
option :content_model, :simple
def process parent, reader, attributes
lines = reader.lines.map {|line| line.upcase.gsub(/\.( |$)/, '!\\1') }
Asciidoctor::Block.new parent, :paragraph, :source => lines, :attributes => attributes
end
end
📎
|
This API is inspired by Java Logging API (JUL).
If you are familiar with |
AsciidoctorJ (v1.5.7+) offers the possibility to capture messages generated during document rendering. These messages correspond to logging information and are organized in 6 severity levels:
-
DEBUG
-
INFO
-
WARN
-
ERROR
-
FATAL
-
UNKNOWN
The easiest way to capture messages is registering a LogHandler
through the Asciidoctor
instance.
Asciidoctor asciidoctor = Asciidoctor.Factory.create();
asciidoctor.registerLogHandler(new LogHandler() { // (1)
@Override
public void log(LogRecord logRecord) {
System.out.println(logRecord.getMessage());
}
});
-
Use
registerLogHandler
to register one or more handlers.
The log
method in the org.asciidoctor.log.LogHandler
interface provides a org.asciidoctor.log.LogRecord
that exposes the following information:
Severity severity |
Severity level of the current record. |
Cursor cursor |
Information about the location of the event, contains:
|
String message |
Descriptive message about the event. |
String sourceFileName |
Contains the value |
String sourceMethodName |
The Asciidoctor Ruby engine method used to convert the file; |
Similarly to AsciidoctorJ extensions, the Log Handling API provides an alternate method to register Handlers without accessing Asciidoctor
instance.
Start creating a normal LogHandler implementation.
package my.asciidoctor.log.MemoryLogHandler;
import java.util.ArrayList;
import java.util.List;
import org.asciidoctor.log.LogHandler;
import org.asciidoctor.log.LogRecord;
/**
* Stores LogRecords in memory for later analysis.
*/
public class MemoryLogHandler extends LogHandler {
private List<LogRecord> logRecords = new ArrayList<>();
@Override
public void log(LogRecord logRecord) {
logRecords.add(record);
}
public List<LogRecord> getLogRecords() {
return logRecords;
}
}
Next, create a file called org.asciidoctor.log.LogHandler
inside META-INF/services
with the implementation’s full qualified name.
my.asciidoctor.log.MemoryLogHandler
And that’s all. Now when a .jar file containing the previous structure is dropped inside classpath of AsciidoctorJ, the handler will be registered automatically.
The Asciidoctor EPUB3 gem (asciidoctor-epub3) is bundled inside the AsciidoctorJ EPUB3 jar (asciidoctorj-epub3). To use it, simply add the asciidoctorj-epub3 jar to your dependencies. The version of the AsciidoctorJ EPUB3 jar aligns with the version of the Asciidoctor EPUB3 gem.
Here’s how you can add the AsciidoctorJ EPUB3 jar to your Maven dependencies:
<dependencies>
<dependency>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctorj-epub3</artifactId>
<version>1.5.0-alpha.15</version>
<scope>runtime</scope>
</dependency>
</dependencies>
Once you’ve added the AsciidoctorJ EPUB3 jar to your classpath, you can set the backend
attribute to epub3
.
The document will be converted to the EPUB3 format.
🔥
|
The asciidoctor-epub3 gem is alpha. While it can be used successfully, there may be bugs and its functionality may change in incompatible ways before the first stable release. In other words, by using it, you are also testing it ;) |
Let’s see an example of how to use AsciidoctorJ with the EPUB3 converter.
= Book Title
Author Name
:imagesdir: images (1)
include::content-document.adoc[] (2)
-
The EPUB3 converter requires the value of the
imagesdir
attribute to beimages
. -
The EPUB3 converter must be run on a spine document that has at least one include directive (and no other body content) in order to function properly.
= Content Title
Author Name
[abstract]
This is the actual content.
== First Section
And off we go.
And finally we can convert the document to EPUB3 using AsciidoctorJ.
asciidoctor.convertFile(new File("spine.adoc"),
options().safe(SafeMode.SAFE).backend("epub3").get()); // (1) (2)
assertThat(new File("target/test-classes/index.epub").exists(), is(true));
-
Currently, the EPUB3 converter must be run in
SAFE
orUNSAFE
mode due to a bug -
epub3
is the name of the backend that must be set to convert to EPUB3.
For output formats that are not natively supported by Asciidoctor it is possible to write an own converter in Java. You can find out more about how to write your own converters using AsciidoctorJ in the Integrator Guide.
Simple extensions may be fully implemented in Java, but if you want to create complex extensions you can mix Ruby and Java code. This means that you may need to execute a Ruby file or a RubyGem (i.e., gem) inside your extension.
To load a Ruby file inside the Ruby runtime, you can use org.asciidoctor.jruby.internal.RubyUtils.loadRubyClass(Ruby, InputStream)
.
You can also load a gem using an API that wraps Ruby’s require
command.
The gem must be available inside the classpath.
Next run org.asciidoctor.jruby.internal.RubyUtils.requireLibrary(Ruby, String)
, passing the name of the gem as the second argument.
Sometimes you may need the Ruby runtime used inside AsciidoctorJ. One reason is because you are using JRuby outside AsciidoctorJ and you want to reuse the same instance. Another reason is that you need to instantiate by yourself an Asciidoctor Ruby object.
To get this instance you can use org.asciidoctor.jruby.internal.JRubyRuntimeContext.get(Asciidoctor)
to get it from a given Asciidoctor instance.
By default, AsciidoctorJ comes with all required gems bundled within the jar. But in some circumstances like OSGi environments you may require to store gems in an external folder and be loaded by AsciidoctorJ.
As the Java interface org.asciidoctor.Asciidoctor
and its factory org.asciidoctor.Asciidoctor.Factory
are agnostic to JRuby there are the interface org.asciidoctor.jruby.AsciidoctorJRuby
and org.asciidoctor.jruby.AsciidoctorJRuby.Factory
that allow to get an Asciidoctor instance using JRuby with a certain GEM_PATH.
Note that org.asciidoctor.jruby.AsciidoctorJRuby
directly extends org.asciidoctor.Asciidoctor
.
import static org.asciidoctor.jruby.AsciidoctorJRuby.Factory.create;
import org.asciidoctor.Asciidoctor;
Asciidoctor asciidoctor = create("/my/gem/path"); // (1)
-
Creates an
Asciidoctor
instance with givenGEM_PATH
location.
In a non OSGi context, the following snippet will successfully create an Asciidoctor object:
import static org.asciidoctor.Asciidoctor.Factory.create;
import org.asciidoctor.Asciidoctor;
Asciidoctor asciidoctor = create();
In an OSGi context it will not work because JRuby needs some paths to find the Asciidoctor gems. In order to make it work, you will need to specify the Asciidoctor gems path using the JavaEmbedUtils class. We will update the previous snippet of code to specify this path:
import static org.asciidoctor.jruby.AsciidoctorJRuby.Factory.create;
import org.asciidoctor.Asciidoctor;
Asciidoctor asciidoctor = create(Arrays.asList("uri:classloader:/gems/asciidoctor-2.2.0/lib")); // (1)(2)
-
uri:classloader:/gems/asciidoctor-<version>/lib
specifies where the gems for Asciidoctor are located. Actually this path is located inside theasciidoctorj-<version>.jar
file -
The version here differs from the AsciidoctorJ version as it corresponds to the version of Asciidoctor, not the AsciidoctorJ one.
📎
|
We consider this code to be placed inside an OSGi bundle |
This solution has pros and cons:
-
Pros: you don’t need to extract the gems located in the asciidoctorj binary ;
-
Cons:
-
the version of asciidoctor is hard coded ;
-
JRuby may start slower than expected versus the C-based Ruby implementation (MRI). Fortunately, JRuby offers flags that can improve the start time and tune applications. Several Java flags can also be used in conjunction with or apart from the JRuby flags in order to improve the start time even more.
For small tasks such as converting an AsciiDoc document, two JRuby flags can drastically improve the start time:
Name | Value |
---|---|
|
RUBY1_9 |
|
OFF |
When using AsciidoctorJ via the API these flags have to be set as system properties when creating the org.asciidoctor.Asciidoctor
instance:
System.setProperty("jruby.compat.version", "RUBY1_9");
System.setProperty("jruby.compile.mode", "OFF");
Asciidoctor asciidoctor = Asciidoctor.Factory.create();
When starting AsciidoctorJ via the CLI these options can be defined in the files .jrubyrc
that are loaded from the current working directory and the home directory of the user.
$ cat ./.jrubyrc
compat.version=RUBY1_9
compile.mode=OFF
$ ./asciidoctorj -V
AsciidoctorJ 1.5.2 [http://asciidoctor.org]
Runtime Environment: jruby 1.7.20 (1.9.3)
📎
|
The properties in these .jrubyrc files do not contain the prefix jruby. .
The property values also must not have trailing blanks!
|
Alternatively you can also set any system properties using the environment variable ASCIIDOCTORJ_OPTS
:
$ export ASCIIDOCTORJ_OPTS=-Djruby.compat.version=RUBY1_9
$ asciidoctorj -V
AsciidoctorJ 1.5.2 [http://asciidoctor.org]
Runtime Environment: jruby 1.7.20 (1.9.3)
The Java flags available for improving start time depend on whether your working on a 32- or 64-bit processor and your JDK version. Let’s see a summary of these flags and in which environments they can be used.
Name | JDK |
---|---|
|
32 bit Java |
|
32/64 bit Java |
|
32/64 bit Java SE 7 |
|
32/64 bit Java SE 7 |
export JAVA_OPTS="-Xverify:none -client"
You can find a full explanation on how to improve the start time of JRuby applications in Optimization.
If you want to use AsciidoctorJ in an application deployed on WildFly, you have to follow the instruction below:
-
Create an Asciidoctor module for WildFly.
-
Create the following folder tree: $JBOSS_HOME/modules/org/asciidoctor/main.
-
Create the module descriptor file module.xml.
Asciidoctor module descriptor for WildFly<?xml version="1.0" encoding="UTF-8"?> <module xmlns="urn:jboss:module:1.0" name="org.asciidoctor"> <resources> <resource-root path="asciidoctorj-api-2.2.0.jar"/> <resource-root path="asciidoctorj-2.2.0.jar"/> <resource-root path="jcommander-1.72.jar"/> <resource-root path="jruby-complete-9.2.9.0.jar"/> </resources> <dependencies> <module name="sun.jdk" export="true"> <imports> <include path="sun/misc/Unsafe" /> </imports> </module> <module name="javax.management.j2ee.api"/> <module name="javax.api"/> <module name="org.slf4j"/> </dependencies> </module>
-
Copy the jar files into the same folder as the module.xml file.
-
Make sure the version numbers of the jar files agree with what’s in the current set. Restart WildFly for the new module to take effect.
-
Add a dependency on your Java archive to this WildFly module using one of the following options:
-
Add the dependency just into the MANIFEST.MF file.
MANIFEST.MF file example with dependency to Asciidoctor moduleManifest-Version: 1.0 Dependencies: org.asciidoctor ...
-
Or, configure the dependency into the pom.xml with the Maven JAR/WAR plugin.
pom.xml file example with Maven WAR plugin configuration to add a dependency... <dependencies> <dependency> <groupId>org.asciidoctor</groupId> <artifactId>asciidoctorj</artifactId> <version>2.2.0</version> <scope>provided</scope> <!--(1)--> ... </dependency> </dependencies> ... <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.4</version> <configuration> <archive> <manifestEntries> <Dependencies>org.asciidoctor</Dependencies> <!--(2)--> </manifestEntries> </archive> </configuration> </plugin> ...
-
The AsciidoctorJ dependency and the transitives dependencies don’t need to be added to the final WAR since all JARs are available through the module.
-
The module dependency will be added to the MANIFEST.MF file.
-
-
Pre-release versions of AsciidoctorJ
are published to Bintray.
You can find them in https://bintray.com/asciidoctor/maven/asciidoctorj/view.
Final releases are released to both Maven Central and Bintray.
Here’s how to use a pre-release version in Maven:
<repositories>
<repository>
<id>central</id>
<name>bintray</name>
<url>http://dl.bintray.com/asciidoctor/maven</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
Snapshot versions will be published to https://oss.jfrog.org. To use a snapshot version of the the AsciidoctorJ library add this repository to your project:
<repositories>
<repository>
<id>oss-jfrog-artifactory</id>
<name>oss-jfrog-artifactory-releases</name>
<url>https://oss.jfrog.org/artifactory/oss-snapshot-local</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
If you build your project using Gradle add the repository like this to your build:
repositories {
maven {
url 'http://oss.jfrog.org/oss-snapshot-local/'
}
}
You can also download a snapshot version of the distribution from here: https://oss.jfrog.org/oss-snapshot-local/org/asciidoctor/asciidoctorj-distribution
AsciidoctorJ is built using Gradle. The project is structured as a multi-module build.
The root folder is the root project and there are several subproject folders, each prefixed with asciidoctorj-. Each subproject produces a primary artifact (e.g., jar or zip) and its supporting artifacts (e.g., javadoc, sources, etc).
The subprojects are as follows:
- asciidoctorj-api
-
The common API for AsciidoctorJ. Other implementations for different platforms than JRuby may reuse and implement this API. Produces the asciidoctorj-api.jar
- asciidoctorj
-
The main Java bindings for the Asciidoctor RubyGem (asciidoctor) running on JRuby. Also bundles optional RubyGems needed at runtime, such as coderay, tilt, haml and slim. Produces the asciidoctorj jar.
- asciidoctorj-distribution
-
Produces the distribution zip that provides the standalone
asciidoctorj
command. - asciidoctorj-epub3
-
Bundles the Asciidoctor EPUB3 RubyGem (asciidoctor-pdf) and its dependencies as the asciidoctorj-epub3 jar.
- asciidoctorj-pdf
-
Bundles the Asciidoctor PDF RubyGem (asciidoctor-pdf) and its dependencies as the asciidoctorj-pdf jar.
- asciidoctorj-diagram
-
Bundles the Asciidoctor Diagram RubyGem (asciidoctor-diagram) and its dependencies as the asciidoctorj-diagram jar.
- asciidoctorj-arquillian-extension
-
Bundles an Arquillian extension that allows to inject an Asciidoctor instance or other instances commonly used by Asciidoctor tests into a test case.
- asciidoctorj-test-support
-
Contains some common test classes that are used by multiple other subprojects and the Arquillian extension.
The Gradle build is partitioned into the following files:
build.gradle gradle.properties settings.gradle gradle/ wrapper/ ... deploy.gradle deploySnapshot.gradle eclipse.gradle providedConfiguration.gradle publish.gradle sign.gradle asciidoctorj-arquillian-extension/ build.gradle asciidoctorj-api/ build.gradle asciidoctorj-core/ build.gradle asciidoctorj-diagram/ build.gradle asciidoctorj-distribution/ build.gradle asciidoctorj-epub3/ build.gradle asciidoctorj-pdf/ build.gradle asciidoctorj-test-support/ build.gradle
You invoke Gradle on this project using the gradlew
command (i.e., the Gradle Wrapper).
💡
|
We strongly recommend that you use Gradle via the Gradle daemon. |
To clone the project, compile the source and build the artifacts (i.e., jars) locally, run:
$ git clone https://github.com/asciidoctor/asciidoctorj cd asciidoctorj ./gradlew assemble
You can find the built artifacts in the asciidoctorj-*/build/libs folders.
To execute tests when running the build, use:
$ ./gradlew build
To only execute the tests, run:
$ ./gradlew check
You can also run tests for a single module:
$ cd asciidoctorj-core ../gradlew check
To run a single test in the asciidoctorj-core subproject, use:
$ ../gradlew -Dsingle.test=NameOfTestClass test
To create the distribution, run:
$ ./gradlew distZip
You can find the distribution in the asciidoctorj-distribution/build/distributions folder.
To import the project into IntelliJ IDEA 14, simply import the project using the import wizard. For more information, see the Gradle page in the IntelliJ IDEA Web Help.
Continuous integration for the AsciidoctorJ project is performed by Travis CI. You can find recent build results, including the build status of pull requests, on the asciidoctor/asciidoctorj page.
Artifacts are published to Maven Central and jCenter by way of Bintray’s Distribution as a Service platform.
Before publishing, you need to configure your gpg signing and Bintray credentials. Create the file $HOME/.gradle/gradle.properties and populate the following properties.
signing.keyId=
signing.password=
signing.secretKeyRingFile=/home/YOUR_USERNAME/.gnupg/secring.gpg
bintrayUsername=
bintrayApiKey=
To build, assemble and sign the archives (jars and distribution zip), run:
$ ./gradlew -PpublishRelease=true signJars
💡
|
The publishRelease=true property is technically only required if the version is a snapshot.
|
To build, assemble (but not sign) and install the archives (jars and distribution zip) into the local Maven repository, run:
$ ./gradlew -PpublishRelease=true install
To build, assemble, sign and publish the archives (jars and distribution zip) to Bintray, run:
$ ./gradlew clean ./gradlew -i -x pMNPTML asciidoctorj-api:bintrayUpload asciidoctorj:bintrayUpload asciidoctorj-distribution:bintrayUpload
🔥
|
Don’t run the clean task in the same execution as the bintrayUpload because it will not upload one of the signatures.
|
If you want to first perform a dry run of the upload, add the dryRun=true
property.
$ ./gradlew -i -PdryRun=true -x pMNPTML asciidoctorj-api:bintrayUpload asciidoctorj:bintrayUpload asciidoctorj-distribution:bintrayUpload
📎
|
The -x pMNPTML is necessary to work around a bug in the publishing plugin that prevents it from signing the archives.
|
❗
|
Bintray does not allow you to publish snapshots. You have to first update the version in gradle.properties to a release (or pre-release) version number. Currently, Gradle is not configured to automatically tag a release, so you have to create the git tag manually. |
To publish a snapshot version simply run:
$ ./gradlew asciidoctorj-api:artifactoryPublish asciidoctorj:artifactoryPublish asciidoctorj-distribution:artifactoryPublish
This will publish the all artifacts that have a snapshot version number to https://oss.jfrog.org.
The source code for AsciidoctorJ, including the latest developments and issues, can be found in the project’s repository on GitHub. If you identify an issue while using AsciidoctorJ, please don’t hesitate to file a bug report. Also, don’t forget to join the Asciidoctor discussion list, where you can ask questions and leave comments.