Calmdevelopment

Keep calm and code. Or do some other stuff.


A little example how to handle custom dates with jbake, using groovy MarkupTemplateEngine, to generate a valid sitemap and atom feed.

Show the world you updated a post

Lets say you wrote a blog post a while ago, maybe September 2016, but you want to update a detail you have missed.

Introduce a new Property

So you open your post update it and add a new jbake Property to your header.

Frank Becker
2016-09-21
:jbake-updated: 21.04.2017 (1)
:jbake-type: post
:jbake-language: en
:jbake-tags: jbake,asciidoctor,asciidoctor-diagram
:jbake-status: published
:jbake-description: How to use asciidoctor-diagram with jbake
:jbake-users-question: https://groups.google.com/d/msg/jbake-user/qjS_ojssKF0/hz60cvI-EgAJ
:bintray-gradle-plugin: https://bintray.com/calmdev/gradle-plugins/jbake-gradle-plugin
:github-pull: https://github.com/jbake-org/jbake/pull/269
:asciidoctor-diagram: https://github.com/asciidoctor/asciidoctor-diagram
:jbake-gradle-plugin: https://github.com/jbake-org/jbake-gradle-plugin
1 A Property called updated with a date String dd.MM.yyyy

Use the property to render the date

Extend your template to show when the post was updated.

A subtemplate representing a post (src/jbake/templates/bricks/post-brick.tpl)
import java.text.SimpleDateFormat

div(class:"row"){
    div(class:"small-12 middle-12 large-12 columns"){
        article(class:"wrap"){
            header{
                div(class:"row"){
                    div(class:"small-3 medium-1 large-1 columns"){
                        include template: 'bricks/date.tpl'
                    }

                    div(class:"small-9 medium-11 large-11 columns"){
                        include template: 'bricks/post-title.tpl'
                    }
                }
                div(class:'row') {
                    div(class:"small-offset-3 medium-offset-1 large-offset-1 small-6 medium-6 large-6 columns") {
                        model.put('tagList',post.tags)
                        include template: 'bricks/tags.tpl'
                    }
                    div(class:"small-3 medium-3 large-3 columns text-right") {
                        if( post.updated ){ (1)
                            strong('Updated: ')
                            yield post.updated
                        }
                    }
                }
                hr()
            }

            div(class:"row"){
                div(class:"columns"){
                    yieldUnescaped post.body
                }
            }
        }
    }
}
1 Render updated property only if set in the post

Add format Strings to your configuration

As you want to render the date in different formats I recommend to add the format strings to your configuration.

That way you can reuse them in different templates.

Adding format strings to the gradle configuration
jbake{
  version = "2.5.1"
  asciidoctorjVersion = "1.5.4.1"
  configuration['blog.title'] = "calmdevelopment"
  configuration['blog.description'] = "'A personal Blog. Mostly about tech stuff. groovy, gradle, asciidoctor, jbake and other interesting stuff that crosses my path...'"
  configuration['db.store'] = "local"
  configuration['db.path']= "build/cache"
  configuration['site.host'] = config.server.url
  configuration['render.tags'] = true
  configuration['site.contextPath'] = config.server.contextPath
  configuration['foundation.version'] = foundationVersion
  configuration['twitter.user'] = "@knarfancho"
  configuration['asciidoctor.option.requires'] = "asciidoctor-diagram"
  configuration['asciidoctor.attributes'] = [
    "sourceDir=${projectDir}",
    "imagesdir=${config.server.contextPath}img",
    "imagesoutdir=${bake.input}/assets/img",
    "source-highlighter=highlight.js",
    "icons=font"
  ]
  configuration['feed.timestamp'] = "yyyy-MM-dd\'T\'HH:mm:ss\'Z\'" (1)
  configuration['sitemap.format'] = 'yyyy-MM-dd' (2)
  configuration['updated.format'] = "dd.MM.yyyy" (3)
}
1 A date format for atom feeds
2 A date format for the sitemap
3 The date format I’m using for the updated property

Update sitemap template

Change the sitemap template to use the updated property to set the last modification date of your post.

The sitemap template (src/jbake/templates/sitemap.tpl)
import java.text.SimpleDateFormat (1)

xmlDeclaration()
urlset( xmlns:'http://www.sitemaps.org/schemas/sitemap/0.9'){
    published_content.each {content ->
        url {

            Date dateUpdated (2)
            if ( content.updated ) { (3)
                dateUpdated = new SimpleDateFormat(config.updated_format).parse(content.updated) (4)
            }

    	    loc("${config.site_host}${config.site_contextPath}${content.uri}")
    	    lastmod("${dateUpdated?dateUpdated.format(config.sitemap_format):content.date.format(config.sitemap_format)}") (5)
        }
    }
}
1 import SimpleDateFormat to format and parse a date string
2 declare a Date variable
3 try to convert the date string if the updated property is set
4 parse the updated date string and format with updated.format from configuration
5 ternary condition to use dateUpdated or the post date to format with sitemap.format from configuration

Update feed template

Now do the same for the feed template.

The sitemap template (src/jbake/templates/feed.tpl)
import java.text.SimpleDateFormat (1)

yieldUnescaped "<?xml version='1.0' encoding='UTF-8'?>"
newLine()
feed(xmlns:"http://www.w3.org/2005/Atom"){

    title("${config.blog_title}")
    newLine()
    link(href:"${config.site_host}${config.site_contextPath}")
    newLine()
    link(rel:"self", type:"application/atom+xml", href:"${config.site_host}${config.site_contextPath}${config.feed_file}")
    newLine()
    subtitle("${config.blog_subtitle?:""}")
    newLine()
    updated("${published_date.format(config.feed_format)}")
    newLine()
    id("tag:${config.feed_id},${published_date.format('yyyy:MM')}")
    newLine()
    published_posts.each {post ->
        entry{
          title("${post.title}")
          newLine()
          author{
              name("${post.author}")
          }
          newLine()
          link(href:"${config.site_host}${config.site_contextPath}${post.uri}")
          newLine()

          Date dateUpdated (2)
          if ( post.updated ) { (3)
              dateUpdated = new SimpleDateFormat(config.updated_format).parse(post.updated) (4)
          }

          updated("${dateUpdated?dateUpdated.format(config.feed_format):post.date.format(config.feed_format)}") (5)
          newLine()
          id("${config.site_host}${config.site_contextPath}${post.uri}")
          newLine()
          post.tags.each { tag ->
            category(term:"${tag}")
            newLine()
          }
          content(type:"html") {
            yield post.body
          }
        }
        newLine()
    }
}
1 import SimpleDateFormat to format and parse a date string
2 declare a Date variable
3 try to convert the date string if the updated property is set
4 parse the updated date string and format with updated.format from configuration
5 ternary condition to use dateUpdated or the post date to format with feed.format from configuration

That’s it!

Okt
10
2016

Amazing News! JBake Version 2.5.0 has finally arrived. Get it while it’s hot!

Download

See the official download page for instructions. Or use my examples.

curl

curl -L http://hash.to/5HQ -o /tmp/jbake-2.5.0-bin.zip

sdkman

sdk i jbake

jbake-gradle-plugin

buildscript {
  repositories {
      maven { url "http://dl.bintray.com/calmdev/gradle-plugins" }
      mavenLocal()
      jcenter()
  }

  dependencies {
    classpath 'me.champeau.gradle:jbake-gradle-plugin:0.3.0-alpha.1'
  }
}

apply plugin: 'me.champeau.jbake'

repositories {
  jcenter()
}

jbake{
  version = "2.5.0"
  asciidoctorjVersion = "1.5.4.1"
}

New Template Engine

My favourite new feature is the groovy MarkupTemplateEngine support.

Try it yourself. Create a new jbake project, bake it, serve it.

mkdir /tmp/groovyMTE-blog
cd /tmp/groovyMTE-blog
jbake -i -t groovy-mte
jbake -b
jbake -s

This enables a more readable and modular template design powered by groovy (version 2.4.7).

I’m so happy! Happy baking everyone!

Updated: 21.04.2017

Since version 2.5.0 of jbake it is possible to use asciidoctor-diagram.

This is a little demonstration of how to use this feature with jbake 2.5.1.

It’s inspired by a question on the jbake user list.

gradle project configuration

Here is an example of my current gradle build file. See source @github for the full example.

build.gradle used to build this blog
buildscript {
  repositories {
      mavenLocal()
      jcenter()
  }

  dependencies {
    classpath 'org.asciidoctor:asciidoctorj-diagram:1.5.0' (2)
  }
}

plugins {
    id 'org.jbake.site' version '1.0.0' (1)
    id 'com.github.ben-manes.versions' version '0.14.0'
    id 'org.akhikhl.gretty' version '1.4.0' apply false
    id 'com.craigburke.bower-installer' version '2.5.1'
    id 'distribution'
}

apply from: 'gradle/distribution.gradle'
apply from: 'gradle/environment.gradle'
apply from: 'gradle/webResources.gradle'

repositories {
  mavenLocal()
  jcenter()
}

if ( env == "local" ){
  apply plugin: 'war'
  apply plugin: 'org.akhikhl.gretty'

  gretty {
    httpPort = config.server.port
    contextPath = config.server.contextPath
    extraResourceBases = [bake.output]
  }
}
else {
  apply from: 'gradle/publish.gradle'
}

afterEvaluate {
println bake.output
}


jbake{
  version = "2.5.1"
  asciidoctorjVersion = "1.5.5"
  configuration['blog.title'] = "calmdevelopment"
  configuration['blog.description'] = "'A personal Blog. Mostly about tech stuff. groovy, gradle, asciidoctor, jbake and other interesting stuff that crosses my path...'"
  configuration['db.store'] = "local"
  configuration['db.path']= "build/cache"
  configuration['site.host'] = config.server.url
  configuration['render.tags'] = true
  configuration['site.contextPath'] = config.server.contextPath
  configuration['foundation.version'] = foundationVersion
  configuration['twitter.user'] = "@knarfancho"
  configuration['asciidoctor.option.requires'] = "asciidoctor-diagram" (3)
  configuration['asciidoctor.attributes'] = [
    "sourceDir=${projectDir}", (4)
    "imagesdir=${config.server.contextPath}img", (5)
    "imagesoutdir=${bake.input}/assets/img", (6)
    "source-highlighter=highlight.js",
    "icons=font"
  ]
  configuration['feed.format'] = "yyyy-MM-dd\'T\'HH:mm:ss\'Z\'"
  configuration['sitemap.format'] = "yyyy-MM-dd"
  configuration['updated.format'] = "dd.MM.yyyy"
}
1 Add asciidoctorj-diagram 1.5.0 to the classpath
2 Add the jbake gradle plugin
3 Configure asciidoctor to require asciidoctor-diagram
4 Set attribute sourceDir to the projects directory to easyly include source files (like this one). e.g.: include::{sourceDir}/build.gradle
5 The location of the image dir referenced in rendered img-tags. e.g: <img src="/blog/img/asciidoctor-diagram-classes.png" alt="asciidoctor diagram classes" width="270" height="283">
6 The output location for the rendered diagram images

Add a diagram to your document

asciidoctor-diagram supports different diagram types. I use a plantuml block with an example copied from the README :)

A sample plantuml block
 [plantuml, "asciidoctor-diagram-classes", "png"]
 ----
 class BlockProcessor
 class DiagramBlock
 class DitaaBlock
 class PlantUmlBlock

 BlockProcessor <|-- DiagramBlock
 DiagramBlock <|-- DitaaBlock
 DiagramBlock <|-- PlantUmlBlock
 ----

The rendered example

asciidoctor diagram classes

That’s awesome!! :)


Older post are available in the archive

2014 - 2017 | Mixed with Foundation v6.2.3 | Baked with JBake v2.5.1