.Ref: ${sku} ---- Descripcion: ${description} Referencia ${sku}, ${price} ---- image::${sku}.png[${description}]
Descargar el script ../scripts/asciidoctor/Catalogo.groovy
25 January 2018
El supuesto que vamos a plantear en este documento es la creación de un catálogo de productos de una tienda.
Dicho catálogo consistirá en un Pdf donde mostraremos, para cada artículo de interés, la descripción, el precio y una imagen del producto.
Para la generación de este catálogo nos vamos a basar en Asciidoctor. Para una consulta rápida sobre esta herramienta puedes consultar el siguiente tutorial, el cual es una guía básica pero completa sobre esta materia. |
En este caso vamos a utilizar imágenes en nuestro local pero podemos apuntar a links donde tengamos nuestras imágenes . En nuestro ejemplo el id de cada item corresponderá con el nombre de imagen a usar para el artículo. |
El schema de nuestra base de datos será algo muy simple, consistente en una única tabla con el id, descripción, precio de cada artículo. |
Nuestro script necesitará conectarse a una base de datos de donde obtendrá la información de cada artículo, y para cada uno de ellos generará una "página" del Pdf. Para ello usaremos un fichero plantilla común a todos, aunque utilizar uno diferente en base a la categoría, precio, etc de cada artículo es una modificación trivial.
.Ref: ${sku} ---- Descripcion: ${description} Referencia ${sku}, ${price} ---- image::${sku}.png[${description}]
= Catalogo de Productos Miguel Rueda <miguel.rueda.garcia@gmail.com> :idprefix: :icons: font :imagesdir: ./images Este es el catálogo de nuestros productos a día de hoy. En el puede encontrar las referencias, junto con precios e imágenes, de cada uno de ellos.
template=new File('./product.tpl').text
catalog= new File('./catalog.tpl').text
query='select * from products where sku < 3'
new File('.').eachFileMatch(~/.*.adoc/) { file ->
file.delete()
}
engine = new groovy.text.SimpleTemplateEngine()
Para empezar a trabajar lo primero es cargar las plantillas anteriormente mencionadas (las del producto: product.tpl y la del catálogo general: catalog.tpl), al igual que la query para la base de datos junto con la condición que requiera el cliente.
El siguiente paso será limpiar todos los posibles ficheros con extensión adoc que podamos tener en la ruta de ejecución de nuestro script
Por último inicializaremos nuestra variable engine que nos servirá para tratar las plantillas.
A continuación pasamos a explicar como cargamos de la base de datos los productos y como posteriormente generamos partiendo de un fichero base nuestros productos.
Para ello utilizaremos la función generateProducts()
la cual se conecta a la base de datos que le indiquemos, ejecutará
la query anteriormente definida y por cada producto llamará al método createProductAdoc
encargado del hacer
el .adoc del producto que recibirá por parámetro:
void generateProducts(){
Sql sql = Sql.newInstance( "jdbc:mysql://localhost:3306/origen?jdbcCompliantTruncation=false",
"user",
"password",
"com.mysql.jdbc.Driver")
sql.eachRow(query){item->
createProductAdoc item
}
}
Mediante el engine previamente inicializado con la plantilla correspondiente conseguiremos generar un fichero para cada artículo donde se sustituyan las variables de la plantilla con los valores del producto en cuestión;
def createProductAdoc(item){
def txt = engine.createTemplate(template).make([
'description':item.description,
'sku':item.sku,
'price':item.price
]).toString()
new File("${item.sku}.adoc").text = txt
}
Para la construcción del catálogo en sí usaremos la misma técnica que para cada producto, utlizando esta vez una plantilla catalog.tpl De esta forma podremos parametrizar el aspecto inicial del catálogo.
Sobre el fichero generado iremos añadiendo directivas asciidoctor para incluir los adoc generados para cada artículo tal como se detalla en el apartado anterior. El resultado final será el fichero catalogo.adoc con tantos includes como artículos hemos obtenido en la consulta:
void generateCatalog() {
def txt = engine.createTemplate(catalog).make([
'today': new Date().format('dd/MM/yyyy HH:mm')
]).toString()
new File("catalogo.adoc").text = txt
Sql sql = Sql.newInstance("jdbc:mysql://localhost:3306/origen?jdbcCompliantTruncation=false",
"user",
"password",
"com.mysql.jdbc.Driver")
sql.eachRow(query) { item ->
new File("catalogo.adoc") << "include::${item.sku}.adoc[]\n"
}
}
Por último nos resta invocar a Asciidoctor para que tomando como base los ficheros generados (catalogo y sus includes) nos genere un Pdf catalogo.pdf
void generatePdf(){
asciidoctor = Factory.create();
attributes = AttributesBuilder.attributes(). // (1)
docType('book').
tableOfContents(true).
sectionNumbers(true).
sourceHighlighter("coderay").
get()
options = OptionsBuilder.options(). // (2)
backend('pdf').
attributes(attributes).
safe(SafeMode.UNSAFE).
get()
asciidoctor.convertFile(new File("catalogo.adoc"), options) // (3)
}
Creamos los atributos que contendrá nuestro fichero asciidoctor. En los cuales podemos indicar el tipo de documento si tendrá o no tabla de contenidos…
Indicamos que opciones para crear nuestro catálogo entre ellas backend('pdf')
ya que es el formato que deseamos obtener
Conversión del adoc a pdf
Si quisiéremos personalizar aún más nuestro pdf podemos crear un "tema" para nuestro pdf y con ello aumentar las
características del mismo. Para ello tenemos que crear un fichero con la extensión yml
en
el que podemos incluir el tipo de fuente, el tamaño, imágenes de fondo y un largo de etcétera de caraterísticas.
Vamos a ver un ejemplo de tema:
title_page: // (1) align: left base: font_family: Times-Roman // (2) font_size: 12 // (3)
Indicamos que el titulo de nuestra imagen está alineado a la izquierda
La fuente de nuestro texto es Times-Roman
El tamaño de letra de es 12
Para que Asciidoctor utilize este tema simplemente hay que indicarlo en los atributos a la hora de su invocación:
asciidoctor = Factory.create();
attributes = AttributesBuilder.attributes().attribute("pdf-style", "tema.yml").
docType('book').
tableOfContents(true).
sectionNumbers(true).
get()
@Grapes([
@Grab(group='org.asciidoctor', module='asciidoctorj', version='1.5.6'),
@Grab(group='org.asciidoctor', module='asciidoctorj-pdf', version='1.5.0-alpha.16'),
@Grab(group='org.jruby', module='jruby-complete', version='9.1.15.0'),
@Grab('mysql:mysql-connector-java:5.1.6')
])
@GrabConfig(systemClassLoader=true)
import groovy.sql.Sql
import org.asciidoctor.OptionsBuilder
import org.asciidoctor.AttributesBuilder
import org.asciidoctor.SafeMode
import org.asciidoctor.Asciidoctor.Factory
//tag::prepararEntorno[]
template=new File('./product.tpl').text
catalog= new File('./catalog.tpl').text
query='select * from products where sku < 3'
new File('.').eachFileMatch(~/.*.adoc/) { file ->
file.delete()
}
engine = new groovy.text.SimpleTemplateEngine()
//end::prepararEntorno[]
generateProducts()
generateCatalog()
generatePdf()
//tag::generateProducts[]
void generateProducts(){
Sql sql = Sql.newInstance( "jdbc:mysql://localhost:3306/origen?jdbcCompliantTruncation=false",
"user",
"password",
"com.mysql.jdbc.Driver")
sql.eachRow(query){item->
createProductAdoc item
}
}
//end::generateProducts[]
//tag::create_adoc[]
def createProductAdoc(item){
def txt = engine.createTemplate(template).make([
'description':item.description,
'sku':item.sku,
'price':item.price
]).toString()
new File("${item.sku}.adoc").text = txt
}
//end::create_adoc[]
//tag::create_catalog[]
void generateCatalog() {
def txt = engine.createTemplate(catalog).make([
'today': new Date().format('dd/MM/yyyy HH:mm')
]).toString()
new File("catalogo.adoc").text = txt
Sql sql = Sql.newInstance("jdbc:mysql://localhost:3306/origen?jdbcCompliantTruncation=false",
"user",
"password",
"com.mysql.jdbc.Driver")
sql.eachRow(query) { item ->
new File("catalogo.adoc") << "include::${item.sku}.adoc[]\n"
}
}
//end::create_catalog[]
//tag::create_pdf[]
void generatePdf(){
asciidoctor = Factory.create();
attributes = AttributesBuilder.attributes(). // (1)
docType('book').
tableOfContents(true).
sectionNumbers(true).
sourceHighlighter("coderay").
get()
options = OptionsBuilder.options(). // (2)
backend('pdf').
attributes(attributes).
safe(SafeMode.UNSAFE).
get()
asciidoctor.convertFile(new File("catalogo.adoc"), options) // (3)
}
//end::create_pdf[]