Skip to content

Commit

Permalink
Comparison document with JINJA templates
Browse files Browse the repository at this point in the history
jamal-cmd does not create jar with dependencies, it does not work
jamal-packaging was added and shell commands were added to create docker image and also a .deb package
If has new parop eval
Env has parop, normal query, or report
  • Loading branch information
verhas committed Jun 14, 2024
1 parent b0c1b6c commit bea9ebc
Show file tree
Hide file tree
Showing 47 changed files with 840 additions and 174 deletions.
2 changes: 1 addition & 1 deletion README.jrf
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# This is a Jamal reference file containing serialized base64 encoded macros
# Created: 2024-06-03 15:53:36 +0200
# Created: 2024-06-14 12:42:03 +0200
# id|openStr|closeStr|verbatim|tailParameter|pure|content|parameters
# TOC
VE9D|eyU=|JX0=|0|0|0|Ci4gPDxJbnN0YWxsYXRpb24+PgouIDw8R1M+PgouIDw8Q29uZmlndXJhdGlvbj4+Ci4gPDxGZWF0dXJlcz4+Ci4gPDxDb250cmlidXRpbmc+PgouIDw8RG9jdW1lbnRhdGlvbj4+Ci4gPDxMaWNlbnNlPj4KLiA8PENoYW5nZWxvZz4+Ci4gPDxSb2FkbWFwPj4KLiA8PFN1cHBvcnQ+PgouIDw8RkFRPj4KLiA8PE1haW50ZW5hbmNlPj4=|
165 changes: 165 additions & 0 deletions documentation/JINJA.adoc.jam
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
= Comparing JINJA Templates to Jamal

JINJA is a templating engine for Python.
It is similar to Jamal that it places directives inside the document.
In most of the cases, you can use Jamal where you use JINJA as the other way around.
These are competing products.

In the following, I will compare JINJA to Jamal along different features.
I am fairly knowledgeable with Jamal, but my knowledge about JINJA is limited, so I might be wrong in some comparisons.
If you feel that some statements in this document are incorrect, please create a pull request correcting them.
I will review the suggested changes, and I reference the contribution.



== License

|===
|Jamal |JINJA

|Apache 2 License
|BSD-3-Clause License

|===

Both products are open source licensed and are available in source code.

== Programming Language

|===
|Jamal |JINJA

|Java

Groovy, Ruby, ScriptBasic, Kotlin, basic
|Python

|language independence, meta-markup
|strongly integrated, template language

|===

JINJA is developed in Python.
Jamal is developed in Java.

Usually, the language of the development is not important for the users of the software.
This is partially true for JINJA.

Although you can use JINJA in any project without caring that it is running in Python, this product is mainly targeted for Python applications.
The primary use of JINJA is to be a Python templating framework.
A good example is the looping construct that iterates over Python lists or dictionaries.

Jamal is written in Java, but its design is not tied to Java.
You can use Jamal in any project.
For example, the looping construct in Jamal is not tied to Java collections, but it can iterate over any list of strings you present in the document.
Looping over Java structures is also possible, but it is not the primary use case.

Jamal also has features, which are tight to Java, but these are implemented in optional modules.

Jamal also supports JVM languages, like Groovy, Scala, Kotlin, etc.
It also supports ScriptBasic and has a simple built-in imperative BASIC like language.

== Extensibility

|===
|Jamal |JINJA

|JVM language macros
|Python code

| IO modules
|

| Debugger
|

|===

JINJA is tightly integrated with implementation language and language features and can be extended with Python code.

Jamal is designed to be modular and can be extended with Java code.
Even the core macros are provided in a separate library and could be replaced with custom implementations.
Macros for Jamal can be written in Java, Groovy, Ruby, Kotlin, or any other JVM language.

Jamal can also be extended with debuggers and IO modules.
The standard installation provides a web-based graphical debugger and IO channels that can open files on the disk (default), in JAR files, Java resources and from the network.

== Integration, Embedding

|===
|Jamal |JINJA

| Command line, Jbang
| Flask

| Maven, Gradle
| Django

| Asciidoctor IntelliJ, AsciidocFX
| Babel

| JavaDoc
| Pylons

|===

Both applications can be embedded into different applications.
JINJA can be embedded into Python applications, Jamal can be embedded into Java applications.
JINJA is integrated with the

* `Flask`,
* `Django`,
* `Babel`, and
* `Pylons`

content management systems.

Jamal is integrated into more Java technology related applications, like Maven, Gradle, JavaDoc, but also into the Asciidoctor plugin in IntelliJ IDEA and AsciidocFX.
This makes it possible to edit Jamal meta markup files interactively in these environments for Asciidoc, Markdown, XML, and other format documents.

== Editor Support

|===
|Jamal |JINJA

| AsciidocFX, IntelliJ IDEA WYSIWYG editing
| PyCharm template support

|===

Jamal can be interactively edited in AsciidoctorFX and IntelliJ IDEA.
If you choose IntelliJ IDEA, you have to install the Asciidoctor plugin in IntelliJ IDEA and configure the editor to treat all your `*.jam` files as AsciiDoc files.
You need also copy the Jamal files from the maven central into the project library.
After that, you can edit Jamal meta-markup enhanced Markdown and Asciidoctor files in IntelliJ.

If you use AsciidoctorFX, you do not need a plugin.
The rest of the steps are the same.

Copying the filed from maven central is automatic, you can run Jamal with a special command line option to do it for you.

You can also download and install IntelliJ IDEA templates that support a bit of syntax autocompletion for Jamal.

JINJA is supported in PyCharm.
It is part of the editor bundled, you only configure the file extensions that you want to use it for.
The editor support is syntactical, highlighting, and code completion and not WYSIWYG editing.

Generally, the editor support is fairly mature for both products.
The lack of WYSIWYG editing in the case of JINJA is not a significant drawback because of the main focus area supporting templates which then are used from program code.

== Debug Support

|===
|Jamal |JINJA

| Interactive Web-based React.js debugger, trace
| trace

|===

Jamal supports a debugger interface, and there is a web-based debugger implemented in React.js.
Using that, you can interactively debug and execute the Jamal evaluation step by step.

It is also possible to generate an XML trace file that will contain all macro evaluations hierarchically.
The format XML was selected because it has a tree structure supporting the hierarchical nature of the macro evaluation, and it also has superb editor support in different editors.

JINJA cannot be debugged interactively, but has extensive tracing facility.
11 changes: 11 additions & 0 deletions documentation/MODULES.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ Input handlers are loaded via the service loader and can load resource files, ma



=== packaging

Directory containing different packaging tools to be executed after the release of the Java code version.
These create different packages, like docker image, Debian package, etc.

== Modules
=== 1. link:https://github.com/verhas/jamal/blob/master/jamal-all/README.adoc[ALL] ^_core_^

Expand Down Expand Up @@ -272,5 +277,11 @@ The code in the directory `jamal-debug-ui` contains the REACT.js based ui for th
This is not a module.
The code in the directory `jamal-docker` contains a Dockerfile to build a Docker image with Jamal.

=== 40. link:https://github.com/verhas/jamal/blob/master/jamal-packaging/README.adoc[PACKAGING] ^_packaging_^



Contains the different packaging code in the subdirectories.



9 changes: 9 additions & 0 deletions documentation/MODULES.adoc.jam
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ Input handlers are loaded via the service loader and can load resource files, ma
{#define ! _{#replace(detectNoChange=false)/$x/-/_/}=.}{@comment makes chapter doubly define an error}
}

=== {category packaging}

Directory containing different packaging tools to be executed after the release of the Java code version.
These create different packages, like docker image, Debian package, etc.

== Modules
{chapter :all:core}
This module contains no code.
Expand Down Expand Up @@ -198,6 +203,10 @@ The code in the directory `jamal-debug-ui` contains the REACT.js based ui for th
This is not a module.
The code in the directory `jamal-docker` contains a Dockerfile to build a Docker image with Jamal.

{chapter :packaging:packaging}

Contains the different packaging code in the subdirectories.

{#define module_directory_count={@listDir (maxDepth=1 pattern=jamal-[\w\-]*$ countOnly) ..}}

{!#if [not equals={module_directory_count}]/{chapter_counter last}/
Expand Down
2 changes: 1 addition & 1 deletion documentation/PAROPS.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ As we have seen, the `include` macro with the parops
uses the `[` and `]` characters.

The built-in core macros use these separator characters.
Currently 13 built-in core macros have parops.
Currently 14 built-in core macros have parops.

The class `Scanner` provides the tools to ease parop parsing.

Expand Down
21 changes: 21 additions & 0 deletions documentation/macros/env.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,27 @@ on the machine where the original `env.adoc.jam` file was converted to ASCIIDOC.

If there is a `?` after the name of the variable name, then the macro will result either the `true` or `false`.
This can be used to test that an environment variable exists or not.
In principle

.Jamal source
[source]
----
{#if|{@env JAVA_HOME}|Java installed|Java not installed}
----

also results

.output
[source]
----
Java installed
----


as anything that is not empty string or the literal `false` is considered `true` in Jamal.
It may happen that the value of the environment variable is `false` and in that case the code would think it is not defined, instead of defined to be `false`.
Also the value of the environment variable may contain the macro separating character

Testing the value of the environment variable in an `{@if ... }` macro may be misleading when the value is literal `false` or an empty string.

Starting with Jamal 1.9.0, it is possible to use `!` after the name of the variable.
Expand Down
14 changes: 14 additions & 0 deletions documentation/macros/env.adoc.jam
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,20 @@ on the machine where the original `env.adoc.jam` file was converted to ASCIIDOC.

If there is a `?` after the name of the variable name, then the macro will result either the `true` or `false`.
This can be used to test that an environment variable exists or not.
In principle

{%sample/
{#if|{@env JAVA_HOME}|Java installed|Java not installed}
%}

also results

{%output%}

as anything that is not empty string or the literal `false` is considered `true` in Jamal.
It may happen that the value of the environment variable is `false` and in that case the code would think it is not defined, instead of defined to be `false`.
Also the value of the environment variable may contain the macro separating character

Testing the value of the environment variable in an `{@if ... }` macro may be misleading when the value is literal `false` or an empty string.

Starting with Jamal {%RELEASE:OBERGLATT%}, it is possible to use `!` after the name of the variable.
Expand Down
6 changes: 5 additions & 1 deletion documentation/macros/if.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ When no options are specified the `test` is true, if
The literal `false` is false using any combination of upper and lower case letters with or without surrounding spaces.

The evaluation of the test string can be modified using options.
There are 11 options.
There are 12 options.


The first three options are "boolean" options.
Expand Down Expand Up @@ -130,6 +130,9 @@ The options
test that the string given as the first parameter is a defined user defined macro, a locally defined macro, or a globally defined macro.
A macro is locally defined if it was defined in the same scope where the `if` is used.

The option

* `eval` aliased as `evaluate` will evaluate the test string before assessing it as a boolean value.

The following examples show a few cases, as demonstrations:

Expand Down Expand Up @@ -165,6 +168,7 @@ The following examples show a few cases, as demonstrations:
{@if [greaterThan=13 not]/13/true/false}=true 13 is not greater than 13, it is the same logic as the previous
{@if [lessThan=13 equals=14]/13/true/false}=false 13 is not less than 13 and does not equal 14
{@if [lessThan=13 and largerThan=2]/12/true/false}=true 12 is in the range (2,13)
{@if [eval]/{a}/true/false}=true {a} is in the range (2,13) as _a_ is defined to be 12
----


Expand Down
9 changes: 7 additions & 2 deletions documentation/macros/if.adoc.jam
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
{%MACRO name="if" since={%RELEASE:ZURICH%}%}


{%@snip:check file=../../jamal-core/src/main/java/javax0/jamal/builtins/If.java hash=9b9c6bfa%}
{%@snip:check file=../../jamal-core/src/main/java/javax0/jamal/builtins/If.java hash=5dfc882d
%}
{%@snip:collect from=../../jamal-core/src/main/java%}\

The `if` macro makes it possible to evaluate the content conditionally.
Expand Down Expand Up @@ -30,7 +31,7 @@ When no options are specified the `test` is true, if
The literal `false` is false using any combination of upper and lower case letters with or without surrounding spaces.

The evaluation of the test string can be modified using options.
There are {%@define nrIfOptions=11%} {%nrIfOptions%} options.
There are {%@def nrIfOptions=12%} options.
{%#snip:check id=if_options lines={%nrIfOptions%} %}

The first three options are "boolean" options.
Expand Down Expand Up @@ -112,6 +113,9 @@ The options
test that the string given as the first parameter is a defined user defined macro, a locally defined macro, or a globally defined macro.
A macro is locally defined if it was defined in the same scope where the `if` is used.

The option

* `eval` aliased as `evaluate` will evaluate the test string before assessing it as a boolean value.

The following examples show a few cases, as demonstrations:

Expand Down Expand Up @@ -147,6 +151,7 @@ they are expected, that way this sample is also a simple integration test of the
{s/{`@if [greaterThan=13 not]/13/true/false}/true} 13 is not greater than 13, it is the same logic as the previous
{s/{`@if [lessThan=13 equals=14]/13/true/false}/false} 13 is not less than 13 and does not equal 14
{s/{`@if [lessThan=13 and largerThan=2]/12/true/false}/true} 12 is in the range (2,13)
{s/{@define a=12}{`@if [eval]/{a}/true/false}/true} {}a} is in the range (2,13) as _a_ is defined to be 12
%}%}

{%output%}
Expand Down
4 changes: 2 additions & 2 deletions jamal-api/src/main/java/javax0/jamal/api/ServiceLoaded.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public interface ServiceLoaded {
*/
static <T> List<T> getInstances(Class<T> klass) {
final var services = getInstances(klass, Thread.currentThread().getContextClassLoader());
if( services.size() > 0 ){
if(!services.isEmpty()){
return services;
}
return getInstances(klass, ServiceLoaded.class.getClassLoader());
Expand All @@ -46,7 +46,7 @@ static <T> List<T> getInstances(Class<T> klass, final ClassLoader cl) {
try {
final ServiceLoader<T> services = ServiceLoader.load(klass, cl);
services.iterator().forEachRemaining(list::add);
if (list.size() == 0) {
if (list.isEmpty()) {
loadViaMetaInf(klass, list, cl);
}
return list;
Expand Down
2 changes: 1 addition & 1 deletion jamal-asciidoc/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.11.0</version>
<version>5.12.0</version>
</dependency>
<dependency>
<groupId>io.github.markdown-asciidoc</groupId>
Expand Down
2 changes: 1 addition & 1 deletion jamal-cmd/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
With the command line version of Jamal you can convert files processing the Jamal meta markup.
You can process a single file or multiple files traversing in a directory structure.

To convert a single file you simply have to specify the input and the output file:
To convert a single file, you simply have to specify the input and the output file:

.Jamal source
[source]
Expand Down
2 changes: 1 addition & 1 deletion jamal-cmd/README.adoc.jam
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ on the help screen and also no option is documented that does not exist
With the command line version of Jamal you can convert files processing the Jamal meta markup.
You can process a single file or multiple files traversing in a directory structure.

To convert a single file you simply have to specify the input and the output file:
To convert a single file, you simply have to specify the input and the output file:

{%sample/ jamal input output %}

Expand Down
Loading

0 comments on commit bea9ebc

Please sign in to comment.