El lenguaje de plantillas de calibre

El lenguaje de plantillas de calibre es un lenguaje específico de calibre que se utiliza en todo calibre para tareas como especificar rutas de archivo, dar formato a valores y calcular el valor de las columnas especificadas por el usuario. Ejemplos:

  • Especifar la estructura de carpetas y los nombres de archivo al guardar archivos de la biblioteca de calibre en el disco o en el lector de libros electrónicos.

  • Definir reglas para añadir iconos y colores a la lista de libros de calibre.

  • Definir columnas virtuales que contienen datos de otras columnas.

  • Búsqueda avanzada en la bibliotecas.

  • Búsqueda y sustitución avanzada de metadatos.

El lenguaje está construido en torno al concepto de una «plantilla», que especifica qué metadatos del libro se usan, las operaciones que se realizan sobre los metadatos y qué formato se aplica.

Plantillas básicas

Una plantilla básica consiste en una o varias expresiones de plantilla. Una expresión de plantilla consiste en texto y nombres entre llaves ({}) que se sustituyen por los metadatos correspondientes del libro que está siendo procesado. Por ejemplo, la plantilla predeterminada de calibre para guardar libros en un dispositivo tiene 4 expresiones de plantilla:

{author_sort}/{title}/{title} - {authors}

Para el libro «The Foundation» de «Isaac Asimov» da lugar a:

Asimov, Isaac/The Foundation/The Foundation - Isaac Asimov

Las barras no son expresiones de plantilla porque no están entre {}. Este tipo de texto se mantiene donde aparece. Por ejemplo, si la plantilla es:

{author_sort} Some Important Text {title}/{title} - {authors}

entonces para «The Foundation» la plantilla produce:

Asimov, Isaac Some Important Text The Foundation/The Foundation - Isaac Asimov

Una expresión de plantilla tiene acceso a todos los metadatos disponibles en calibre, incluidas las columnas personalizadas que haya creado, usando su el nombre de búsqueda de una columna. Para obtener el nombre de búsqueda o consulta de una columna (también llamada campo), pase el cursor sobre el encabezado de la columna en la lista de libros de calibre. Los nombres de búsqueda para las columnas personalizadas siempre empiezan por #. Para columnas personalizadas de tipo serie, siempre hay un campo adicional llamado #nombre de búsqueda_index que es el índice de serie para el libro en la serie. Por ejemplo, si tiene una columna personalizada de serie llamada #miserie, también habrá una columna llamada #miserie_index. La columna de índice para la serie normal se llama series_index.

Además de los campos basados en columnas normales, también puede usar:

  • {formats} - Una lista de los formatos disponibles en la biblioteca de calibre para un libro

  • {identifiers:select(isbn)} - El ISBN del libro

Si un campo de metadatos para un libro determinado no está definido, entonces el campo en la plantilla se sustituye por un texto vacío (''). Por ejemplo, considere la siguiente plantilla:

{author_sort}/{series}/{title} {series_index}

Si el libro de Asimov «Second Foundation» está en la serie «Foundation», la plantilla produce:

Asimov, Isaac/Foundation/Second Foundation 3

Si no se ha introducido la serie para el libro, la plantilla produce:

Asimov, Isaac/Second Foundation

El procesador de plantillas elimina automáticamente barras múltiples y espacios iniciales o finales.

Formato avanzado

Además de sustituir metadatos, las plantillas pueden incluir texto adicional de manera condicional y controlar el formato de los datos sustituidos.

Incluir texto de mane condicional

A veces puede querer que aparezca un texto en la salida sólo si un campo no está vacío. Un caso común es series y series_index, para los que puede querer o nada o ambos valores separados por un guión. calibre tiene en cuenta este caso usando una sintaxis de expresión de plantilla especial.

Por ejemplo, y usando el caso anterior de la serie «Foundation», suponga que quiere que la plantilla produzca Foundation - 3 - Second Foundation. Esta plantilla cumple el cometido:

{series} - {series_index} - {title}

Sin embargo, si un libro no tiene serie, la plantilla producirá - - el título, que probablemente no sea lo que deseaba. Normalmente preferiría que el resultado fuese el título sin los guiones. Puede conseguir esto usando la siguiente sintaxis de plantilla:

{campo:|prefijo|sufijo}

Esta expresión de plantilla dice que si campo tiene el valor XXXX, el resultado será prefijoXXXXXsufijo. Si campo está vacío (no tiene ningún valor) el resultado será un texto vacío (nada), porque el prefijo y el sufijo se ignoran. Tanto el prefijo como el sufijo pueden contener espacios.

No use subplantillas ({…}) o funciones (ver más adelante) en el prefijo o el sufijo.

Usando esta sintaxis, podemos resolver el problema anterior de los libros sin serie con esta plantilla:

{series}{series_index:| - | - }{title}

Los guiones se incluirán solamente si el libro tiene índice de serie, que sólo tendrá si tiene una serie. Continuando con el ejemplo de la serie «Foundation», la plantilla producirá Foundation - 1 - Second Foundation.

Notas:

  • Debe incluir los dos puntos tras el nombre de búsqueda si usa un prefijo o sufijo.

  • Debe incluir ambos caracteres | o ninguno. No está permitido usar sólo uno como en {campo:| - }.

  • Es posible asignar un texto vació para el prefijo o sufijo, como en {series:|| - }. La plantilla {title:||} es lo mismo que {title}.

Formato

Supongamos que queremos asegurarnos de que series_index aparezca con dígitos, con ceros a la izquierda. Se consigue de esta manera:

{series_index:0>3s} - Tres dígitos con ceros a la izquierda

Para obtener ceros a la derecha use:

{series_index:0<3s} - Tres dígitos con ceros a la derecha

Si usa índices de serie con valores fraccionarios (por ejemplo 1.1), puede querer asegurarse de que los decimales queden alineados. Por ejemplo, puede que los índices 1 y 2.5 aparezcan como 01.00 y 02.50 para que se ordenen correctamente en un dispositivo que utilice un orden lexicográfico. Para ello, use:

{series_index:0>5.2f} - Cinco caracteres que incluyen dos dígitos con cero a la izquierda, un punto decimal y dos dígitos tras el punto decimal.

Si quiere sólo las dos primeras letras de los datos, use:

{author_sort:.2} - Sólo las primeras dos letras del orden de autor

Gran parte del formato del lenguaje de plantillas de calibre proviene de Python. Para obtener más detalles sobre la sintaxis de estas operaciones de formato avanzadas, vea la documentación de Python (en inglés).

Usar plantillas para definir columnas personalizadas

Las plantillas pueden usarse para mostrar información que no está en los metadatos de calibre o para mostrar los metadatos de una manera diferente al formato normal de calibre. Por ejemplo, puede querer mostrar el ISBN, un campo que calibre no muestra. Puede conseguirlo creando una columna personalizadad de tipo columna generada a partir de otras columnas (en lo sucesivo llamadas columnas compuestas), e introduciendo una plantilla para generar el texto mostrado. La columna mostrará el resultado de evaluar la plantilla. Por ejemplo, para mostrar el ISBN, cree la columna e introduzca {identifiers:select(isbn)} en el cuadro de plantilla. Para mostrar una columna que contenga los valores de dos campos personalizados de serie separados por una coma, use {#serie1:||,}{#serie2}.

Las columnas compuestas pueden utilizar cualquier opción de plantilla, incluidas las de formato.

Nota: No puede modificar los datos mostrados en una columna compuesta, debe modificar las columnas de origen. Si modifica una columna compuesta, por ejemplo pulsando dos veces sobre ella, calibre abrirá la plantilla para modificarla, no los datos resultantes.

Usar funciones en plantillas: modo de función única

Supongamos que desea mostrar el valor de un campo en mayúsculas, aunque normalmente el valor del campo tiene sólo las iniciales en mayúscula. Puede conseguir esto usando las funciones de plantilla. Por ejemplo, para mostrar el título en mayúsculas use la función uppercase, como en {title:uppercase()}. Para mostrarlo con las iniciales en mayúscula use {title:titlecase()}.

Las funciones van en la parte del formato de la plantilla, después de : y antes del primer | o del } de cierre si no se usa ningún prefijo o sufijo. Si tiene tanto un formato como una referencia de función, la función va después de otro :. Las funciones devuelven el valor de la columna especificada en la plantilla, modificado de manera adecuada.

La sintaxis para usar funciones es una de:

{lookup_name:function(arguments)}
{lookup_name:format:function(arguments)}
{lookup_name:function(arguments)|prefix|suffix}
{lookup_name:format:function(arguments)|prefix|suffix}

Los nombres de función deben is siempre seguidos de paréntesis de apertura y cierre. Algunas funciones requieren valores adicionales (argumentos), y éstos van dentro de los paréntesis. Los argumentos se separan por comas. Una coma literal (como texto, no como separador de argumentos) debe ir precedida de una barra invertida (\). El último (o único) argumento no puede contener un paréntesis de cierre textual.

Las funciones se evalúan antes de las especificaciones de formato y del prefijo y sufijo. Véase más abajo un ejemplo de cómo usar un formato y una función.

Importante: Si tiene experiencia en programación, tenga en cuenta que la sintaxis del modo de función única no es la que podría esperarse. Los textos van sin comillas y los espacios son importantes. Todos los argumentos se interpretan como constantes; no hay expresiones.

No use subplantillas ({…}) como argumentos de función. En su lugar, use el modo de programación de plantilla o el modo de programación general.

Algunas funciones requieren expresiones regulares. En el lenguaje de plantillas, las expresiones regulares no distinguen entre mayúsculas y minúsculas.

En la documentación de funciones que se presenta a continuación, la notación [algo]* significa que algo puede repetirse cero o más veces. La notación [algo]+ significa que algo se repite una o más veces (debe existir al menos una vez).

Las funciones pensadas para usarse en modo de función única son:

  • capitalize() – devuelve el valor con la primera letra mayúscula y el resto en minúsculas.

  • contains(patrón, texto_si_coincide, texto_si_no_coincide) – comprueba si el valor coincide con la expresión regular patrón. Devuelve texto_si_coincide si el patrón coincide con el valor, en caso contrario devuelve texto_si_no_coincide.

  • count(separador) – interpreta el valor como una lista de elementos separados por ­separador y devuelve el número de elementos de la lista. La mayoría de las listas usan una coma como separador, pero authors usa un «ampersand» (&). Ejemplos: {tags:count(,)}, {authors,count(&)}. Sinónimos: count(), list_count()

  • format_number(plantilla) – interpreta el valor como un número y le da formato usando una plantilla de formato de Python como {0:5.2f} o {0:,d} o ${0:5,.2f}. La plantilla de formato debe empezar por {0: y terminar por }, como en los ejemplos anteriores. Excepción: puede omitir el {0: inicial y el } final si la plantilla de formato contiene sólo un formato. Véase la documentación del lenguaje de plantillas y de Python para más ejemplos. Devuelve un texto vacío si el formato falla.

  • human_readable() – espera que el valor sea un número y devuelve un texto que representa ese número en KB, MB, GB, etc.

  • ifempty(texto_si_vacío) – si el valor no está vacío, devuelve el valor del campo, en caso contrario devuelve texto_si_vacío.

  • in_list(separador, [ patrón, encontrado, ]* no_encontrado) – interpreta el valor como una lista de elementos separados por separador y comprueba patrón para cada elemento de la lista. Si patrón coincide con algún elemento, devuelve encontrado, en caso contrario devuelve no_encontrado. La pareja de argumentos patrón y encontrado puede repetirse tantas veces como se desee, lo que permite devolver diferentes valores según el valor del elemento. Los patrones se evalúan en orden y se devuelve la primera coincidencia.

  • language_strings(localizar) – devuelve los nombres de los idiomas identificados por los códigos de idioma pasados como valor. Ejemplo {languages:language_strings()}. Si localizar es cero, devuelve los nombres en inglés. Si localizar no es cero, devuelve los nombres en el idioma actual. Los códigos de idioma son una lista separada por comas.

  • list_item(índice, separador) – interpreta el valor como una lista de elementos separados por separador y devuelve el elemento número índice. El primer elemento es el número cero. El último elemento tiene índice -1 y puede obtenerse con list_item(-1,separador). Si el elemento no está en la lista devuelve un texto vacío.

  • lookup([ patrón, clave, ]* clave_alternativa) – Los patrones se comparan con el valor en orden. Si un patrón coincide, se devuelve el valor del campo indicado por clave. Si no coincide ningún patrón, se devuelve el valor del campo indicado por clave_alternativa. Véase switch (más abajo).

  • lowercase() – devuelve el valor del campo en minúsculas.

  • rating_to_stars(usar_media_estrella) – Devuelve la calificación como caracteres de estrella (). El valor debe ser un número entre 0 y 5. Ponga usar_media_estrella a 1 si quiere caracteres de media estrella para números fraccionarios, disponibles con columnas personalizadas de calificación.

  • re(patrón, sustitución) – devuelve el valor después de aplicar la expresión regular. Todas las veces que aparezca patrón en el valor se sustituirá por sustitución. El lenguaje de plantillas usa ``expresiones regulares de Python <https://docs.python.org/3/library/re.html>`_, sin distinguir mayúsculas y minúsculas.

  • select(clave) – interpreta el valor como una lista de elementos separados por comas, con cada elemento de la forma id:valor (el formato de la columna identifier de calibre). La función encuentra la primera pareja con id igual a clave y devuelve el valor correspondiente. Si no se encuentra el id la función devuelve un texto vacío.

  • shorten(car_izq, texto_medio, car_der) – devuelve una versión abreviada del valor, consistente en un número car_izq de caracteres del principio del valor, seguidos de texto_medio, seguido de un número car_der de caracteres del final del valor. car_izq y car_der deben ser números enteros no negativos. Ejemplo, supongamos que quiere mostrar el título con una longitud máxima de 15 caracteres. Una plantilla que hace esto es {title:shorten(9,-,5)}. Para un libro con el título Novísima recopilación de las leyes de España el resultado será Novísima -spaña: los primeros 9 caracteres del título, un - y los últimos 5 caracteres. Si la longitud del valor es menor que car_izq + car_der + la longitud de texto_medio, se usará el valor intacto. Por ejemplo, el título La colmena no se cambiará.

  • str_in_list(separador, [ texto, encontrado, ]+ no_encontrado) – interpreta el valor como una lista de elementos separados por separador, y compara texto con cada valor de la lista. El argumento texto no es una expresión regular. Si texto es igual a alguno de los valores (sin distinción de mayúsculas y minúsculas), devuelve el correspondiente encontrado. Si texto contiene separador, se interpreta también como una lista y se compara cada subvalor. La pareja de argumentos texto y encontrado puede repetirse tantas veces como se desee, lo que permite devolver diferentes valores según el valor de texto. Los textos se comparan en orden. Se devuelve la primera coincidencia.

  • subitems(índice_inicio, índice_fin) – Esta función separa listas de elementos jerárquicos de tipo etiqueta, tales como los géneros. Interpreta val como una lista de elementos separados por comas, donde cada elemento es a su vez una lista de elementos separados por puntos. Devuelve una nueva lista formada tomando de cada elemento los componentes entre las posiciones índice_inicio e índice_fin y combinando los resultados. Se eliminan los duplicados. El primer subelemento de cada lista separada por puntos ocupa la posición cero. Si un índice es negativo, se cuenta desde el final de la lista. Como caso especial, si índice_fin es cero, se considera que es el final de la lista.

    Ejemplos:

    • Suponiendo que la columna #genero contiene A.B.C:

      • {#genero:subitems(0,1)} devuelve A

      • {genero:subitems(0,2)} devuelve A.B

      • {#genero:subitems(1,0)} devuelve B.C

    • Suponiendo que la columna #genero contiene A.B.C, D.E:

      • {#genero:subitems(0,1)} devuelve A, D

      • {#genero:subitems(0,2)} devuelve A.B, D.E

  • sublist(índice_inicio, índice_fin, separador) – interpreta el valor como una lista de elementos separados por separador y devuelve una nueva lista con los elementos comprendidos entre la posición índice_inicio e índice_fin. El primer elemento ocupa la posición cero. Si un índice es negativo, se cuenta desde el final de la lista. Como caso especial, si índice_fin es cero, se considera que es el final de la lista.

    Ejemplos suponiendo que la columna tags (separada por comas) contiene A, B, C:

    • {tags:sublist(0,1,\,)} devuelve A

    • {tags:sublist(-1,0,\,)} devuelve C

    • tags:sublist(0,-1,\,)} devuelve A, B

  • swap_around_articles(separador) – devuelve el valor con los artículos puestos al final. El valor puede ser una lista, en cuyo caso se procesará cada elemento de la lista. Si el valor es una lista, debe proporcionar el separador de los elementos de la lista. Si no se proporciona ningún separador, la lista se trata como un único valor, no una lista. Los artículos son los que calibre usa para generar el orden de título.

  • swap_around_comma() – dado un valor de la forma B, A, devuelve A B. Esto es útil para convertir nombres en formato APELLIDO, NOMBRE a NOMBRE APELLIDO. Si no hay ninguna coma en el valor, la función devuelve el valor sin cambios.

  • switch([patrón, valor,]+ otro_valor) – para cada pareja patrón, valor, comprueba si el valor contiene coincidencias para la expresión regular patrón y, en tal caso, devuelve el valor asociado. Si no coincide ningún patrón, devuelve otro_valor. Pueden emplearse tantas parejas patrón, valor como se desee. Se devuelve la primera coincidencia.

  • test(texto_si_no_vacío, texto_si_vacío) – devuelve texto_si_no_vacío si el valor no está vacío, devuelve texto_si_vacío en caso contrario.

  • titlecase() – devuelve el valor del campo con las iniciales en mayúscula.

  • transliterate() – Devuelve un texto en el alfabeto latino formado por aproximación del sonido de las palabras en el campo de origen. Por ejemplo, si el campo de origen es Фёдор Миха́йлович Достоевский la función devuelve Fiodor Mikhailovich Dostoievskii.

  • uppercase() – devuelve el valor del campo en mayúsculas.

Usar funciones y formato en la misma plantilla

Supongamos que tiene una columna personalizada con números enteros #myint, que quiere mostrar con ceros a la izquierda, como en 003. Una posibilidad es usa como formato 0>3s. Sin embargo, de manera predeterminada, si un número (entero o decimal) es igual a cero, el valor se muestra como un texto vacío, así que el valor cero producirá un texto vacío, no 000. Si quiere ver los valores como 000, debe usar tanto el texto de formato como la función ifempty para cambiar el valor vacío a cero de nuevo, la plantilla sería:

{#myint:0>3s:ifempty(0)}

Tenga en cuenta que puede usar también prefijo y sufijo. Si desea que el número aparezca como [003] o [000], use la plantilla:

{#myint:0>3s:ifempty(0)|[|]}

Modo de programación general

El Modo de programación general (MPG) sustituye las expresiones de plantilla por un programa escrito en el lenguaje de plantillas. La sintaxis del lenguaje está definida por la siguiente gramática:

program         ::= 'program:' expression_list
expression_list ::= top_expression [ ';' top_expression ]*
top_expression  ::= or_expression
or_expression   ::= and_expression [ '||' and_expression ]*
and_expression  ::= not_expression [ '&&' not_expression ]*
not_expression  ::= [ '!' not_expression ]* | compare_exp
compare_expr    ::= add_sub_expr [ compare_op add_sub_expr ]
compare_op      ::= '==' | '!=' | '>=' | '>' | '<=' | '<' | 'in' | 'inlist' |
                    '==#' | '!=#' | '>=#' | '>#' | '<=#' | '<#'
add_sub_expr    ::= times_div_expr [ add_sub_op times_div_expr ]*
add_sub_op      ::= '+' | '-'
times_div_expr  ::= unary_op_expr [ times_div_op unary_op_expr ]*
times_div_op    ::= '*' | '/'
unary_op_expr   ::= [ add_sub_op unary_op_expr ]* | expression
expression      ::= identifier | constant | function | assignment | field_reference |
                    if_expr | for_expr | break_expr | continue_expr |
                    '(' expression_list ')'
field_reference ::= '$' [ '$' ] [ '#' ] identifier
identifier      ::= id_start [ id_rest ]*
id_start        ::= letter | underscore
id_rest         ::= id_start | digit
constant        ::= " string " | ' string ' | number
function        ::= identifier '(' expression_list [ ',' expression_list ]* ')'
assignment      ::= identifier '=' top_expression
if_expr         ::= 'if' condition 'then' expression_list
                    [ elif_expr ] [ 'else' expression_list ] 'fi'
condition       ::= top_expression
elif_expr       ::= 'elif' condition 'then' expression_list elif_expr | ''
for_expr        ::= 'for' identifier 'in' list_expr
                    [ 'separator' separator_expr ] ':' expression_list 'rof'
list_expr       ::= top_expression
break_expr      ::= 'break'
continue_expr   ::= 'continue'
separator_expr  ::= top_expression

Notas:

  • una top_expression siempre tiene un valor. El valor de una expression_list es el valor de la última top_expression de la lista. Por ejemplo, el valor de la expression_list 1;2;'blabla';3 es 3.

  • En un contexto lógico, cualquier valor que no sea vacío es True (verdadero)

  • En un contexto lógico, el valor vacío es False (falso)

  • Textos y números pueden usarse indistintamente. Por ejemplo, 10 y '10' son lo mismo.

  • Los comentarios son líneas que empiezan por un carácter #. No se permiten comentarios que empiecen a mitad de línea.

Prioridad de operadores

La prioridad de los operadores (orden de evaluación) de mayor (se evalúa primero) a menor (se evalúa el último) es:

  • Llamadas a función, constantes, expresiones entre paréntesis, expresiones de declaración, expresiones de asignación, referencias de campo.

  • Más (+) y menos (-) unarios. Estos operadores se evalúan de derecha a izquierda.

    Estas y todas las otras operaciones aritméticas devuelven enteros si la expresión resulta en una parte decimal igual a cero. Por ejemplo, si la expresión devuelve 3.0 se cambia a 3.

  • Multiplicación (*) y división (/). Estas operaciones son asociativas y se evalúan de izquierda a derecha. Use paréntesis si quiere cambiar el orden de evaluación.

  • Suma (+) y resta (-). Estas operaciones son asociativas y se evalúan de izquierda a derecha.

  • Comparaciones numéricas y de textos. Estas operaciones devuelven '1' si la comparación tiene éxito, en caso contrario un texto vacío (''). Las comparaciones no son asociativas: a < b < c es un error de sintaxis.

  • Negación lógica unaria (!). Esta operación devuelve '1' si la expresión es False (da como resultado un texto vacío), en caso contrario ''.

  • Y lógico (&&). Esta operación devuelve '1' si ambas expresiones a derecha e izquierda son True, o un texto vacío ('') si alguna es False. Es asociativa, se evalúa de izquierda a derecha y con cortocircuito https://chortle.ccsu.edu/java5/Notes/chap40/ch40_2.html.

  • O lógico (||). Esta operación devuelve '1' si alguna de las expresiones a derecha e izquierda es True, o un '' si ambas son False. Es asociativa, se evalúa de izquierda a derecha y con cortocircuito https://chortle.ccsu.edu/java5/Notes/chap40/ch40_8.html.

Referencias de campo

Una field_reference da como resultado el valor del campo de metadatos indicado por el nombre de búsqueda que sigue al $ o $$. Usar $ es equivalente a usar la función field. Usar $ es equivalente a usar la función raw_field. Ejemplos:

* $authors ==> field('authors')
* $#genre ==> field('#genre')
* $$pubdate ==> raw_field('pubdate')
* $$#my_int ==> raw_field('#my_int')

Expresiones condicionales

Las expresiones condicionales (if_expression) evalúan primero la condition. Si la condition es True (un valor no vacío) entonces se evalúa expression_list en la sentencia then. Si es False, entonces se evalúa expression_list en la sentencia elif o else, si existen. Las partes elif y else son opcionales. Las palabras if, then, elif, else y fi están reservadas, no pueden usarse como nombres de identificador. Se pueden añadir espacios y saltos de línea donde sea conveniente. La condition es una top_expression, no usa expression_list, no se permite punto y coma. Los elementos de tipo expression_list son secuencias de top_expression separadas por punto y coma. Una expresión condicional devuelve el resultado de la última top_expression en la expression_list evaluada, o un texto vacío si no se evaluó ninguna expression_list.

Ejemplos:

* program: if field('series') then 'yes' else 'no' fi
* program:
      if field('series') then
          a = 'yes';
          b = 'no'
      else
          a = 'no';
          b = 'yes'
      fi;
      strcat(a, '-', b)

Ejemplo de if anidado:

program:
  if field('series') then
    if check_yes_no(field('#mybool'), '', '', '1') then
      'yes'
    else
      'no'
    fi
  else
    'no series'
  fi

Como se ha mencionado, un if produce un valor. Esto significa que todas las siguientes expresiones son equivalentes:

* program: if field('series') then 'foo' else 'bar' fi
* program: if field('series') then a = 'foo' else a = 'bar' fi; a
* program: a = if field('series') then 'foo' else 'bar' fi; a

Como último ejemplo, este programa devuelve el valor de la columna series si el libro tiene una serie, en caso contrario el valor de la columna title:

program: field(if field('series') then 'series' else 'title' fi)

Expresiones de bucle

Una expresión de bucle (for_expression) itera sobre una lista de valores, procesando uno cada vez. La list_expression debe resultar en el nombre de búsqueda de un campo de metadatos, como tags o #genero, o una lista de valores. Si el resultado es un nombre de búsqueda válido, se obtiene el valor del campo y se usa el separador especificado para ese tipo de campo. Si el resultado no es un nombre de búsqueda válido, se supone que es una lista de valores. La lista se supone separada por comas, a no ser que use la palabra clave opcional separator, en ese caso los valores de la lista deben estar separados por el resultado de evaluar separator_expr. Cada valor de la lista se asigna a la variable especificada y luego se evalúa expression_list. Puede usar break para salir del bucle y continue para comenzar con la siguiente iteración.

Ejemplo: Esta plantilla elimina el primer nombre jerárquico para cada valor de Género (#genre`), construyendo una lista con los nuevos nombres.

program:
  new_tags = '';
  for i in '#genre':
    j = re(i, '^.*?\.(.*)$', '\1');
    new_tags = list_union(new_tags, j, ',')
  rof;
  new_tags

Si el Género original es Historia.Militar, Ciencia ficción.Historia alternativa, Léeme, la plantilla devolverá Militar, Historia alternativa, Léeme. Puede usar esta plantilla en Modificar metadatos en masa > Buscar y sustituir con Buscar establecido en plantilla para eliminar el primer nivel de la jerarquía y asignar el valor resultante a Género.

Nota: la última línea en la plantilla, new_tags, no es estrictamente necesaria en este caso, porque for devuelve el valor de la última top_expression en expression_list. El valor de una asignación (assignment) es el valor de su expresión, así que el valor del for es lo que se asignó a new_tags.

Operadores de relación

Los operadores de relación devuelven '1' si la comparación es cierta, en caso contrario devuelven un texto vacío ('').

Hay dos formas de operadores de relación: comparaciones de texto y comparaciones numéricas.

Las comparaciones de texto usan el orden lexicográfico y no distinguen mayúsculas y minúsculas. Las comparaciones de texto permitidas son ==, !=, <, <=, >, >=, in e inlist. El operador in es True si el valor de la expresión de la izquierda, interpretado como una expresión regular, coincide con el valor de la expresión de la derecha. El operador inlist es True si el valor de la expresión de la izquierda, interpretado como una expresión regular coincide con alguno de los elementos de la lista de la derecha, en la que los elementos están separados por comas. Las comparaciones no distinguen mayúsculas y minúsculas.

Los operadores de comparación numérica son ==#, !=#, <#, <=#, ># y >=#. Las expresiones de la izquierda y la derecha deben resultar en valores numéricos con dos excepciones: Tanto el valor textual None (campo no definido) como el texto vacío equivalen al valor cero.

Ejemplos:

  • program: field('series') == 'lala' devuelve '1' si la serie del libro es lala, en caso contrario devuelve ''.

  • program: 'l.a' in field('series') devuelve '1' si la serie del libro coincide con la expresión regular l..a (por ejemplo, lala, El asesino de reyes, etc.), en caso contrario devuelve ''.

  • program: 'ciencia' inlist field('#genero') devuelve '1' si alguno de los géneros del libro coincide con la expresión regular ciencia (por ejemplo Ciencia, Historia de la ciencia, Ciencia ficción, etc.), en caso contrario devuelve ''.

  • program: '^ciencia$' inlist field('#genero') devuelve '1' si alguno de los géneros del libro coincide con la expresión regular ^ciencia$ (por ejemplo Ciencia). Los géneros Historia de la ciencia y Ciencia ficción no coinciden. Si no hay ninguna coincidencia, devuelve ''.

  • program: if field('series') != 'lala' then 'nana' else 'blabla' fi devuelve 'nana' si la serie del libro no es lala, en caso contrario devuelve 'blabla'.

  • program: if field('series') == 'lala' || field('series') == '1632' then 'sí' else 'no' fi devuelve 'sí' si la serie es lala o 1632, en caso contrario devuelve 'no'.

  • program: if '^(lala|1632)$' in field('series') then 'sí' else 'no' fi devuelve 'sí' si la serie es lala o 1632, en caso contrario devuelve 'no'.

  • program: if 11 > 2 then 'sí' else 'no' fi devuelve 'no' porque el operador > realiza una comparación lexicográfica.

  • program: if 11 ># 2 then 'sí' else 'no' fi devuelve 'sí' porque el operador ># realiza una comparación numérica.

Otras funciones disponibles

Las siguientes funciones están disponibles, además de las descritas en el modo de función única.

En el MPG todas las funciones descritas en el modo de función única requieren un primer argumento adicional que especifique el valor sobre el que operan. Todos los argumentos son de tipo expression_list (ver la gramática más arriba).

  • add(x [, y]*) – devuelve la suma de sus argumentos. Da un error si algún argumento no es un número. En la mayoría de los casos puede usarse el operador + en lugar de esta función.

  • and(valor [, valor]*) – devuelve '1' si todos los valores son no vacíos, en caso contrario devuelve un texto vacío. Pueden usarse tantos valores como se desee. En la mayoría de los caso se puede usar el operador && en lugar de esta función. Un motivo para no sustituir and por && es cuando la evaluación en cortocircuito puede cambiar el resultado debido a los efectos secundarios. Por ejemplo, and(a='',b=5) realizará las dos asignaciones, mientra que el operador && no realizará la segunda.

  • assign(id, val) – asigna val a id y devuelve val. id debe ser un identificador, no una expresión. En la mayoría de los casos puede usarse el operador = en lugar de esta función.

  • approximate_formats() – devuelve una lista separada por comas de formatos asociados con el libro. No hay garantía de que esta lista sea correcta, aunque probablemente lo sea. Esta función, y otras que no tienen argumentos, puede usarse en el modo de programación de plantillas (ver más adelante) usando la plantilla {:'approximate_formats()'}. Tenga en cuenta que los nombres de formato resultantes están siempre en mayúsculas, como en «EPUB». La función approximate_formats() es bastante más rápida que las funciones formats_... que se discuten más adelante.

  • author_links(val_separator, pair_separator) – devuelve un texto que contiene una lista de autores y los enlaces de dichos autores de la forma:

    author1 val_separator author1_link pair_separator author2 val_separator author2_link etc.
    

    Cada autor está separado de su correspondiente enlace por el texto val_separator, sin espacios adicionales. Los pares author:linkvalue están separados por el texto pair_separator, sin espacios adicionales. Es responsabilidad del usuario proporcionar separadores que no aparezcan en los nombres o enlaces de autor. El nombre de autor se incluye aunque su enlace esté vacío.

  • author_sorts(separador) – devuelve un texto que contiene la lista de valores de orden de autor para los autores del libro. El orden de autor es el que figura en los metadatos de información autores (diferente del valor de orden de autor del libro). La lista devuelta es de la forma orden_de_autor_1 separador orden_de_autor_2, etc. Los valores de orden de autor en la lista están en el mismo orden que los autores del libro. Si quiere espacios alrededor de separador, inclúyalos en el valor de separador.

  • booksize() – devuelve el valor del campo «tamaño» de calibre. Devuelve '' si no hay formatos.

  • check_yes_no(nombre_de_campo, no_definido, es_false, es_true) – comprueba si el valor del campo de tipo sí o no identificado por el nombre de búsqueda nombre_de campo es uno de los valores especificado en los parámetros. Devuelve “”yes”` si coincide, y un texto vació en caso contrario. Establezca el parámetro no_definido, es_false o es_true a 1 (el número) para comprobar dicha condición, en caso contrario establézcalos a 0. Ejemplo:

    check_yes_no("#bool", 1, 0, 1) devuelve 'yes' si el campo de sí o no #bool es True o no definido (ni True ni False).

    Más de uno de entre no_definido, es_false y es_true pueden ser 1.

  • ceiling(x) – devuelve el menor entero que es mayor o igual a x. Da un error si x no es un número.

  • character(nombre_carácter) – devuelve el carácter con nombre nombre_carácter. Por ejemplo, character('newline') devuelve un carácter de salto de línea ('\n'”). Los nombres de carácter admitidos son newline (salto de línea), return (retorno de carro), tab (tabulación) y backslash (barra invertida).

  • cmp(x, y, mn, ig, my) – compara x e y después de convertirlas en números. Devuelve mn si x <# y, ig si x ==# y y my en caso contrario. Esta función puede sustituirse normalmente por uno de los operadores de comparación numérica (==#, <#, >#, etc.).

  • connected_device_name(ubicación_de_almacenamiento) – si hay un dispositivo conectado, devuelve el nombre del dispositivo, en caso contrario devuelve un texto vacío. Cada ubicación de almacenamiento de un dispositivo tiene un nombre diferente. Los nombres de ubicación_de_almacenamiento son 'main', 'carda' y 'cardb'. Esta función sólo está disponible en la interfaz gráfica.

  • connected_device_uuid(ubicación_de_almacenamiento) – si un dispositivo está conectado, entonces devuelve el uuid (identificador único) del dispositivo, de lo contrario devuelve un texto vacío. Cada ubicación de almacenamiento de un dispositivo tiene un uuid diferente. Los nombres de ubicación_de_almacenamiento son 'main', 'carda' y 'cardb'. Esta función sólo está disponible en la interfaz gráfica.

  • current_library_name() – devuelve la última parte de la ruta a la biblioteca de calibre actual.

  • current_library_path() – devuelve la ruta completa a la biblioteca de calibre actual.

  • date_arithmetic(fecha, cálculo, fmt) – Calcula una nueva fecha a partir de fecha usando cálculo. Devuelve la nueva fecha con el formato opcional fmt: si so se proporciona, el resultado estará en formato ISO. El argumento cálculo es un texto formado por pares vQ (valorQué) donde v es un número que puede ser negativo y Q es una de las letras siguientes:

    • s: añade v segundos a fecha

    • m: añade v minutos a fecha

    • h: añade v horas a fecha

    • d: añade v días a fecha

    • w: añade v semanas a fecha

    • y: añade v años a fecha, donde un año son 365 días.

    Ejemplo: '1s3d-1m' añade 1 segundo, añade 3 días y resta 1 minuto a fecha.

  • days_between(fecha1, fecha2) – devuelve el número de días entre fecha1 y fecha2. El número es positivo si fecha1 es posterior a fecha2, en caso contrario es negativo. Si fecha1 o fecha2 no son fechas, la función devuelve un texto vacío.

  • divide(x, y) – devuelve x / y. Da un error si x o y no son números. Esta función puede sustituirse a menudo por el operador /.

  • eval(texto) – evalúa texto como un programa, pasando las variables locales. Esto permite usar el procesador de plantillas para elaborar resultados complejos a partir de variables locales. En el modo de programación de plantillas, dado que los caracteres { y } se interpretan antes de evaluar la plantilla, debe usarse [[ en lugar de { y ]] para }. Se convertirán automáticamente. Tenga en cuenta que los prefijos y sufijos (la sintaxis |prefijo|sufijo|) no pueden usarse en el argumento de esta función en el modo de programación de plantillas.

  • field(nombre_de_búsqueda) – devuelve el campo de metadatos identificado por nombre_de_búsqueda.

  • field_exists(nombre_campo) – comprueba si existe un campo (columna) con el nombre de búsqueda nombre_campo, devuelve '1' si es así y un texto vacío si no.

  • finish_formatting(val, formato, prefijo, sufijo) – aplica el formato, prefijo y sufijo a un valor de la misma manera que se haría en una plantilla como {series_index:05.2f| - |- }. Esta función se proporciona para facilitar la conversión de plantillas complejas en modo de función única o de plantilla a plantillas MPG. Por ejemplo, el siguiente programa produce la misma salida que la plantilla anterior:

    program: finish_formatting(field("series_index"), "05.2f", " - ", " - ")
    

    Otro ejemplo: para la plantilla {series:re(([^\s])[^\s]+(\s|$),\1)}{series_index:0>2s| - | - }{title} use:

    program:
      strcat(
        re(field('series'), '([^\s])[^\s]+(\s|$)', '\1'),
           finish_formatting(field('series_index'), '0>2s', ' - ', ' - '),
           field('title')
      )
    
  • first_matching_cmp(val, [ cmp, resultado, ]* otro_resultado) – compara val < cmp consecutivamente y devuelve el resultado correspondiente a la primera comparación que sea cierta. Devuelve otro_resultado si ninguna comparación es cierta. Ejemplo:

    i = 10;
    first_matching_cmp(i,5,"small",10,"middle",15,"large","giant")
    

    devuelve "large". El mismo ejemplo con un primer valor de 16 devuelve "giant".

  • first_non_empty(valor [, valor]*) – devuelve el primer valor que no esté vacío. Si todos los valores están vacíos, se devuelve también un texto vacío. Puede incluir tantos valores como quiera.

  • floor(x) – devuelve el mayor entero que es menor o igual a x. Da un error si x no es un número.

  • format_date(val, formato_fecha) – da formato a un valor, que debe ser un texto de fecha, según formato_fecha y devuelve un texto. Los códigos de formato son:

    • d: el día del mes como un número sin cero a la izquierda (de 1 a 31)

    • dd: el día del mes como un número con cero a la izquierda (de 01 a 31)

    • ddd: el nombre del día de la semana traducido y abreviado (por ejemplo, de «lun» a «dom»)

    • dddd: el nombre del día de la semana completo traducido (por ejemplo, de «lunes» a «domingo»)

    • M: el mes como un número, sin cero a la izquierda (de 1 a 12)

    • MM: el mes como un número con cero a la izquierda (de 01 a 12)

    • MMM: el nombre del mes traducido y abreviado (por ejemplo, de «ene» a «dic»)

    • MMMM: el nombre del mes completo traducido (por ejemplo, de «enero» a «diciembre»)

    • yy: el año como un número de dos dígitos (de 00 a 99)

    • yyyy: el año como un número de cuatro dígitos.

    • h: la hora sin cero a la izquierda (de 0 a 11 o de 0 a 23, según am/pm)

    • hh: la hora con un cero a la izquierda (de 00 a 11 o de 00 a 23, según am7pm)

    • m: el minuto sin cero a la izquierda (de 0 a 59)

    • mm: el minuto con cero a la izquierda (de 00 a 59)

    • s: el segundo sin cero a la izquierda (de 0 a 59)

    • s: el segundo con cero a la izquierda (de 00 a 59)

    • ap: se usa un reloj de 12 horas en lugar de 24, con ap sustuido por el text traducido para «am» o «pm».

    • AP: se usa un reloj de 12 horas en lugar de 24, con AP sustuido por el text traducido para «AM» o «PM».

    • iso: la fecha con hora y zona horaria. Debe ser el único formato presente

    • to_number: convierte la fecha y hora en un número décimal (un «código de tiempo»)

    • from_number: convierte un número decimal (un «código de tiempo») en una fecha con formato iso. Si desea un formato diferente, añada el texto de formato desado depués de from_number y dos puntos (:). Ejemplo: from_number:dd MMM yyyy

    Puede obtener resultados inesperados si la fecha a la que se da formato contiene nombres de meses traducidos, lo que puede ocurrir si ha modificado los ajustes de formato de fecha para incluir MMMM. En este caso, en lugar de usar la función field() como en:

    format_date(field('pubdate'), 'yyyy')
    

    use la función raw_field(), como en:

    format_date(raw_field('pubdate'), 'yyyy')
    
  • formats_modtimes(formato_fecha) – devuelve una lista separada por comas de elementos separados por dos puntos (FMT:FECHA) que contienan las fechas de modificación para los formatos de un libro. El argumento formato_fecha especifica cómo se da formato a la fecha. Véase la función format_date para más detalles. Puede usar la función select para obtener la fecha de modificación de un formato específico. Tenga en cuenta que los nombres de formato siempre están en mayúsculas, como en «EPUB».

  • formats_paths() – devuelve una lista separada por comas de elementos separados por dos puntos (FMT:RUTA) que contienen la ruta completa a los formatos de un libro. Puede usar la función select para obtener la ruta a un formato específico. Tenga en cuenta que los nombres de formato están siempre en mayúsculas, como en «EPUB».

  • formats_sizes() – devuelve una lista separada por comas de elementos separados por dos puntos (FMT:TAMAÑO) que contienen los tamaños en bytes de los formatos de un libro. Puede usar la función select para obtener el tamaño de un formato específico. Tenga en cuenta que los nombres de formato siempre están en mayúsculas, como en «EPUB».

  • fractional_part(x) – devuelve el valor tras el punto decimal. Por ejemplo, fractional_part(3.14) devuelve 0.14. Da un error si x no es un número.

  • has_cover() – devuelve 'Yes' si el libro tiene portada, en caso contrario devuelve un texto vacío.

  • is_marked() – comprueba si el libro está «marcado» en calibre, Si lo está, devuelve el valor de la marca, bien 'true' (en minúsculas) o bien una lista separada por comas de los nombres de marca. Devuelve '' (un texto vacío) si el libro no está marcado. Esta función sólo está disponible en la interfaz gráfica.

  • language_codes(nombres) – devuelve los códigos de idioma correspondientes a nombres. Los nombres deben estar en el idioma actual. El argumento nombres es una lista separada por comas.

  • list_contains(valor, separador, [ patrón, encontrado, ]* no_encontrado) – (Sinónimo de in_list) Interpreta el campo como una lista de elementos separados por separador y evalúa patrón con cada valor de la lista. Si patrón coincide con alguno de los elementos de la lista, devuelve encontrado, en caso contrario devuelve no_encontrado. Los argumentos patrón y encontrado pueden repetirse tantas veces como se desee, lo que permite devolver diferentes valores según la búsqueda. Los patrones se evalúan en orden. Se devuelve la primera coincidencia. Sinónimos: in_list(), list_contains()

  • list_count(valor, separador) – interpreta valor como una lista de elementos separados por ­``separador`` y devuelve el número de elementos de la lista. Sinónimos: count(), list_count()

  • list_count_matching(lista, patrón, separador) – interpreta lista como una lista de elementos separados por ­`separador` y devuelve el número de elementos de la lista que coinciden con la expresión regular patrón. Sinónimos: list-count_matching(), count_matching()

  • list_difference(lista1, lista2, separador) – devuelve una lista construida eliminando de lista1 cualquier elemento que aparezca en lista2, sin distinguir mayúsculas y minúsculas. Los elementos de lista1 y lista2 están separados por separador, así como los de la lista resultante.

  • list_equals(lista1, sep1, lista2, sep2, val_sí, val_no) – devuelve val_sí si lista1 y lista2 contienen los mismos elementos, en caso contrario devuelve val_no. Los elementos se determinan dividiendo cada lista por el correspondiente carácter separador (sep1 o sep2). El orden de los elementos no es relevante. La comparación no diferencia mayúsculas y minúsculas.

  • list_intersection(lista1, lista2, separador) – devuelve una lista construida eliminando de lista1 cualquier elemento que no aparezca en lista2, sin distinguir mayúsculas y minúsculas. Los elementos de lista1 y lista2 están separados por separador, así como los de la lista resultante.

  • list_re(lista_orig, separador, incluir, sust_opc) – construye una lista separando primero lista_orig en elementos usando el carácter separador. Para cada elemento en la lista, comprueba si coincide con la expresión regular incluir. Si coincide, se añade a la lista final. Si sust_opc no es un texto vacío, se aplica la sustitución antes de añadir el elemento a la lista final.

  • list_re_group(lista_orig, separador, incluir, búsqueda [, plantilla_grupo]*) – como list_re, pero las sustituciones no son opcionales. Usa re_group(elemento, búsqueda, plantilla_grupo ...) para hacer sustituciones..

  • list_remove_duplicates(lista, separador) – devuelve una lista construida por eliminación de los duplicados en lista. No distingue mayúsculas y minúsculas, se mantiene la última versión. Los elementos de lista están separados por separador, así como los de la lista resultante.

  • list_sort(lista, dirección, separador) – devuelve lista ordenada lexicográficamente sin distinción de mayúsculas y minúsculas. Si dirección es cero, la lista se ordena de manera ascendente, en caso contrario, de manera descendente. Los elementos de lista están separados por separador, así como los de la lista resultante.

  • list_split(lista, sep, prefijo_id) – divide la lista en valores separados por sep y asigna los valores a variables locales con nombre prefijo_id_N, donde N es la posición del valor en la lista. El primer elemento tiene posición 0 (cero). La función devuelve el último elemento de la lista.

    Ejemplo:

    list_split('one:two:foo', ':', 'var')
    

    es equivalente a:

    var_0 = 'one';
    var_1 = 'two';
    var_2 = 'foo
    
  • list_union(lista1, lista2, separador) – devuelve una lista construida por combinación de los elementos en lista1 y lista2, eliminando los duplicados de lista2 (no distingue mayúsculas y minúsculas, se mantiene la versión de lista1). Los elementos de lista1 y lista2 están separados por separador, así como los de la lista resultante. Sinónimos: merge_list(), list_union()

  • mod(x, y) – devuelve floor del resto de x / y. Da un error si x o y no son números.

  • multiply(x [, y]*) – devuelve el producto de sus argumentos. Da un error si algún argumento no es un número. Esta función puede sustituirse a menudo por el operador *.

  • not(valor) – devuelve el texto '1' si el valor está vacío, en caso contrario, devuelve un texto vacío. Esta función puede sustituirse a menudo por el operador de negación unario (!).

  • ondevice() – devuelve el texto 'Yes' si ondevice está activado, si no, devuelve un texto vacío.

  • or(valor [, valor]*) – devuelve el texto '1' si alguno de los valores no está vacío, en caso contrario, devuelve un texto vacío. Pueden incluirse tantos valores como se desee. Esta función puede sustituirse a menudo por el operador ||. Un motivo para no sustituirla es si la evaluación en cortocircuito puede cambiar los resultados debido a efectos secundarios.

  • print(a [, b]*) – escribe los argumentos en la salida estándar. Sólo será visible si inicia calibre a partir de línea de órdenes (calibre-debug -g). La función print siempre devuelve un texto vacío.

  • raw_field(nombre_de_búsqueda [, predeterminado_opcional]) – devuelve el campo de metadatos nombrado por nombre_de_búsqueda sin aplicar ningún formato. Evalúa y devuelve el segundo argumento opcional predeterminado_opcional si el campo no está definido (None).

  • raw_list(nombre_de_búsqueda, separador) – devuelve la lista de metadatos nombrada por nombre_de_búsqueda sin aplicar ningún formato ni ordenación, con los elementos separados por separador.

  • re_group(valor, patrón [, plantilla_para_grupo]*) – devuelve un texto formado por aplicación de la expresión regular patrón a valor, sustituyendo cada coincidencia con el texto devuelto por la correspondiente plantilla. En el modo de programación de plantillas, como en las funciones template y eval, debe usarse [[ en lugar de { y ]] en lugar de }.

    El siguiente ejemplo busca una serie con más de una palabra y pone la primera en mayúsculas:

    program: re_group(field('series'), "(\S* )(.*)", "{$:uppercase()}", "{$}")'}
    
  • round(x) – devuelve el entero más cercano a x. Da un error si x no es un número.

  • series_sort() – devuelve el valor de orden de serie.

  • strcat(a [, b]*) – puede tomar cualquier número de argumentos. Devuelve texto formado por la concatenación de todos los argumentos.

  • strcat_max(máx, texto1 [, prefijo2, texto2]*) – devuelve un texto formado por concatenación de los argumentos. El valor devuelto es inicialmente texto1. Se van añadiendo textos formados por parejas prefijo, texto al final del valor mientras la longitud del resultado sea menor que máx. Los prefijos pueden estar vacíos. El resultado es siempre al menos texto1, aunque su longitud sea mayor que máx. Pueden especificarse tantas parejas prefijo, texto como se desee.

  • strcmp(x, y, mn, ig, my) – hace una comparación lexicográfica sin distinción de mayúsculas y minúsculas entre x e y como textos. Devuelve mn si x < y, ig si x == y, my en otros casos. Esta función puede sustituirse a menudo por los operadores de comparación lexicográfica (==, >, <, etc.)

  • strlen(valor) – Devuelve la longitud del texto valor.

  • substr(texto, inicio, fin) – devuelve los caracteres entre la posición inicio y fin de texto. El primer carácter de texto está en la posición cero. Si fin es negativo, entonces indica la posición contando desde la derecha. Si fin es cero, indica el último carácter. Por ejemplo, substr('12345', 1, 0) devuelve 2345, y substr('12345', 1, -1) devuelve 234.

  • subtract(x, y) – devuelve x - y. Da un error si x o y no son números. Esta función puede sustituirse a menudo por el operador -.

  • today() – devuelve un texto para la fecha y hora hoy (ahora). Este valor está preparado para usarse con format_date o days_between, pero puede manipularse como cualquier otro texto. La fecha está en formato ISO.

  • template(x) – evalúa x como una plantilla. La evaluación se hace en su propio contexto, lo que significa que las variables no comparten entre quien llama a la función y la evaluación de la plantilla.

Programas más complejos en expresiones de plantilla: modo de programación de plantillas

El modo de programación de plantillas (MPP) es una mezcla entre el modo de programación general y el modo de función única. El MPP se diferencia del modo de función única en que permite escribir expresiones de plantilla que hacen referencia a otros campos de metadatos, usar funciones anidadas, modificar variables y hacer operaciones aritméticas. Se diferencia del modo de programación general en que la plantilla está entre caracteres { y } y no empieza por la palabra program. La parte del programa de la plantilla es una expression_list del modo de programación general.

Un ejemplo: supongamos que quiere una plantilla que muestre la serie de un libro si la tiene, y en caso contrario muestre el valor del campo personalizado #genre. Esto no se puede hacer en el modo de función única, porque no se puede hacer referencia a otro campo en la expresión de la plantilla. En el MPP sí se puede. La siguiente expresión lo demuestra:

{#series:'ifempty($, field('#genre'))'}

El ejemplo muestra varias cosas:

  • El MPP se usa si la expresión empieza por :' y termina por '. Cualquier otra cosa se supone que corresponde al modo de función única.

  • la variable $ representa el campo nombrado en la plantilla sobre la que opera la expresión, #series en este caso.

  • las funciones deben llevar todos sus argumentos. No hay valores predeterminados. Por ejemplo, las funciones estándar predefinidas deben tener un parámetro inicial que indique el campo de origen.

  • los espacios en blanco se ignoran y se pueden utilizar en cualquier lugar dentro de la expresión.

  • los textos constantes se encierran en comillas del mismo tipo, ya sea ' o ".

Todas las funciones descritas en el modo de función única y en el modo de programación general pueden usarse en el MPP.

En el MPP, usar los caracteres { y } en textos literales puede conducir a errores o resultados inesperados porque confunden al procesador de plantillas. Éste intenta interpretarlos como límites de expresiones de plantilla y no como caracteres. En algunos casos, pero no todos, puede sustituir un { por [[ y un } por ]]. En general, si un program contiene caracteres { y }, debería usar el modo de programación general.

Como en el modo de programación general, para las funciones descritas en el modo de función única debe proporcionar el valor sobre el que opera la función como primer argumento, además de los argumentos descritos. En el MPP puede usar $ para acceder al valor especificado por el nombre de búsqueda de la expresión de plantilla.

Plantillas guardadas de modo de programa general

El modo de programación general permite guardar plantillas e invocarlas desde otra plantilla, casi como invocar funciones guardadas. Puede guardar plantillas en Preferencias > Avanzado > Funciones de plantilla. Hay más información en el diálogo correspondiente. Puede invocar una plantilla de la misma manera que una función, pasando argumentos por posición si lo desea. Un argumento puede ser una expresión. Ejemplos para invocar una plantilla, suponiendo que la plantilla guardada se llame foo:

  • lala() – invoca la plantilla sin pasar argumentos.

  • lala(a, b) – invoca la plantilla pasando los valores de las variables a y b.

  • lala(if field('series') then field('series_index') else 0 fi) – si el libro tiene series, pasa el valor de series_index, en caso contrario pasa el valor 0.

Puede obtener el valor de los argumentos pasados en la invocación de la plantilla guardada usando la función arguments. Esta función declara e inicializa las variables locales, parámetros en la práctica. Las variables son posicionales: obtienen el valor del argumento usado en la misma posición en la invocación. Si el argumento correspondiente no aparece en la invocación, arguments asigna a esa variable el valor predeterminado suministrado. Si no hay valor predeterminado, será un texto vacío. Por ejemplo, la siguiente función arguments declara dos variables: key y ``alternate`:

arguments(key, alternate='series')

Ejemplos, suponiendo de nuevo que la plantilla guardada se llame lala:

  • lala('#miserie') – a la variable key se le asigna el valor '#miserie' y a la variable alternate se le asigna el valor predeterminado 'serie'.

  • lala('series', '#genero') a la variable key se le asigna el valor 'series' y a la variable alternate se le asigna el valor '#genero'.

  • lala() – a la variable key se le asigna un texto vacío y a la variable alternate se le asigna el valor predeterminado 'series'.

Una buena manera de probar las plantillas guardadas es usar el diálogo Prueba de plantillas. Para facilitar su acceso, asígnele un atajo de teclado en Preferencias > Avanzado > Atajos > Prueba de plantillas. Si le asigna un atajo de teclado podrá alternar rápidamente entre la prueba de plantillas y la modificación del código de programa de la plantilla.

Pasar información adicional a las plantillas

Un desarrollador puede decidir pasar información adicional al procesador de plantillas, como metadatos del libro específicos para una aplicación o información sobre lo que se quiere que haga el procesador. Una plantilla puede acceder a esta información y usarla durante la evaluación.

Desarrollador: cómo pasar información adicional

La información adicional es un diccionario Python que contiene pares nombre_de_variable: valor de variable donde los valores deberían ser textos. La plantilla puede acceder al diccionario, creando variables locales con nombre nombre_de_variable y valor valor de variable. El usuario no puede cambiar el nombre, así que lo mejor es usar nombres que no entren en conflicto con otras variables locales, por ejemplo añadiendo un guión bajo al principio del nombre.

El diccionario se pasa al procesador de plantillas (el formatter) usando el argumento global_vars=diccionario. La forma completa del método es:

def safe_format(self, fmt, kwargs, error_value, book,
                column_name=None, template_cache=None,
                strip_results=True, template_functions=None,
                global_vars={})

Creador de plantillas: cómo acceder a la información adicional

Puede acceder a la información adicional (el diccionario globals) en una plantilla usando la función de plantilla:

globals(id[=expression] [, id[=expression]]*)

donde id es cualquier nombre de variable permitido. Esta función comprueba si la información adicional prevista por el desarrollador contiene el nombre. Si es así, la función asigna el valor a una variable local con ese nombre. Si el nombre no está presente en la información adicional y se suministra una expresión, se evalua dicha expresión y el resultado se asigna a la variable local. Si no existe ni un valor ni una expresión, la función asigna el texto vacío ('') a la variable local.

Una plantilla puede establecer un valor en el diccionario globals usando la función de plantilla:

set_globals(id[=expression] [, id[=expression]]*)

Esta función asigna la pareja id:valor del diccionario globals, donde valor es el valor de la variable local de la plantilla id. Si la variable no existe, valor se toma como el resultado de evaluar expresión.

Notas sobre las diferencias entre modos

Los tres modos de programación, el modo de funcíon única (MFU), el modo de programación de plantillas (MPP) y el modo de programación general (MPG) funcionan de distinta manera. MFU pretende ser «sencillo» y oculta muchos elementos del lenguaje de programación.

Diferencias:

  • En el MFU el valor de la columna se pasa siempre como un primer argumento «invisible» a la función que se incluye en la plantilla.

  • El MFU no hace distinciones entre variables y textos; todos los valores son textos.

  • La siguiente plantilla MFU devuelve el nombre de la serie o el texto 'no series':

    {series:ifempty(no series)}
    

    La plantilla equivalente en MPP es:

    {series:'ifempty($, 'no series')'}
    

    La plantilla equivalente en MPG es:

    program: ifempty(field('series'), 'no series')
    

    El primer argumento de ifempty es el valor del campo series. El segundo argumento es el texto no series. En MFU el primer argumento, el valor, se pasa automáticamente (es el argumento invisible).

  • Varias funciones de plantilla, como booksize() y current_library_name(), no admiten argumentos. Debido al «argumento invisible», no puede usar estas funciones en MFU.

  • Las funciones anidadas, en las que una función invoca a otra función para evaluar un argumento, no pueden usarse en MFU. Por ejemplo, esta plantilla, que pretende devolver los primeros cinco caracteres del valor de la serie convertidos en mayúsculas, no funcionará en MFU:

    {series:uppercase(substr(0,5))}
    
  • MPP y MPG permiten usar funciones anidadas. La plantilla anterior en MPP sería:

    {series:'uppercase(substr($, 0,5))'}
    

    En MPG sería:

    program: uppercase(substr(field('series'), 0,5))
    
  • Como se mencionó ateriormente en la sección modo de programación de plantillas, en el MPP, usar los caracteres { y } en textos literales puede conducir a errores o resultados inesperados porque confunden al procesador de plantillas. Éste intenta interpretarlos como límites de plantilla y no como caracteres. En algunos casos, pero no todos, puede sustituir un { por [[ y un } por ]]. En general, si un program contiene caracteres { y }, debería usar el modo de programación general.

Funciones de plantilla Python definidas por el usuario

Puede añadir funciones propias al procesador de plantillas. Dichas funciones pueden usarse en cualquiera de los tres modos de programación de plantillas. Las funciones se añaden en Preferencias > Avanzado > Funciones de plantilla. Las instrucciones se muestran en el correspondiente cuadro de diálogo.

Notas especiales para plantillas de guardado o envío

Cuando una plantilla se usa como plantilla de «guardado a disco» o de «envío a dispositivo», ocurre un procesado especial. Los valores de los campos se sanean, eliminando caracteres especiales para los sistemas operativos por guiones bajos, incluyendo barras. Esto significa que el texto de los campos no puede usarse para crear carpetas. Sin embargo, las barras no se modifican en los textos de prefijo o sufijo, por lo que las barras en estos textos harán que se creen carpetas. Gracias a esto, es posible crear estructuras de carpetas de profundidad variable.

Por ejemplo, supongamos que quiere una estructura de carpetas serie/índice de serie - título, con la salvedad de que si la serie no existe el título debe estar en la carpeta superior. La plantilla para conseguir esto es:

{series:||/}{series_index:|| - }{title}

La barra y el guión sólo aparecen si la serie no está vacía.

La función lookup() nos permite realizar un procesado aún más complejo. Por ejemplo, supongamos que si un libro tiene una serie, entonces queremos una estructura de carpetas serie/índice de serie - título. Si el libro no tiene una serie, entonces queremos la estructura género/orden de autor/título. Si el libro no tiene género, queremos que use «Desconocido». Queremos seguir dos caminos completamente distintos según el valor de la serie.

Para lograr esto:

  1. Creamos un campo compuesto (démosle el nombre de consulta #aa) que contiene {series}/{series_index} - {title}. Si la serie no está vacía, esta plantilla produce serie/número_de_serie - título.

  2. Creamos un campo compuesto (démosle el nombre de consulta #bb) que contenga {#genre:ifempty(Desconocido)}/{author_sort}/{title}. Esta plantilla produce género/orden de autor/título, donde un género vacío se sustituye por Desconocido.

  3. Establecemos la plantilla de guardado en {series:lookup(.,#aa,#bb)}. Esta plantilla elige el campo compuesto #aa si la serie no está vacía y el campo compuesto #bb si la serie está vacía. Obtenemos por lo tanto dos rutas de guardado completamente diferentes según el campo series esté o no vacío.

Plantillas y controles de metadatos

Los paneles de conexiones se usan para cambiar los metadatos escritos en los libros durante las operaciones de guardado en disco y de envío a dispositivo. Un panel de conexiones le permite especificar una plantilla para suministrar los datos que se escribirán en los metadatos del libro. Puede usar los paneles de conexiones para modificar los siguientes campos: authors, author_sort, language, publisher, tags, title, title_sort. Esa función es útil para los que quieren usar metadatos diferentes en los libros de los dispositivos, para solucionar problemas de ordenación o de visualización.

Cuando cree un panel de conexiones, especifique el formato y dispositivo para los que se usará. Hay un dispositivo especial save_to_disk, que se usa para guardar formatos (en lugar de enviarlos a un dispositivo). Una vez que ha elegido el formato y dispositivo, elija los campos de metadatos para cambiar, y suministre plantillas para obtener los nuevos valores. Estas plantillas están conectadas con sus campos de destino, de ahí el nombre panel de conexiones. Por supuesto, puede usar columnas compuestas en estas plantillas.

Cuando un panel de conexiones pueda aplicarse (servidor de contenido, guardado en disco o envío a dispositivo), calibre busca los paneles definidos para elegir el correcto según el formato y dispositivo. Por ejemplo, para encontrar el panel de conexiones apropiado para enviar un libro EPUB a un dispositivo ANDROID, calibre busca en los paneles en el siguiente orden:

  • un panel de conexiones con una coincidencia exacta de formato y dispositivo, por ejemplo: EPUB y ANDROID

  • un panel de conexiones con una coincidencia exacta de formato y el dispositivo especial any device, por ejemplo EPUB y any device

  • un panel de conexiones con el formato especial any format y una coincidencia exacta de dispositivo, por ejemplo: any format y ANDROID

  • un panel de conexiones con any format y any device

Los campos etiquetas y autores tienen un trato especial, debido a que ambos pueden tener más de un elemento. Un libro puede poseer varias etiquetas y varios autores. Cuando indique que desea cambiar uno de estos campos, la plantilla se examina para comprobar si hay más de un elemento. Para las etiquetas, el resultado se divide dondequiera que calibre encuentre una coma. Por ejemplo, si la plantilla produce el valor Intriga, Terror, el resultado serán dos etiquetas: Intriga y Terror. No existe manera de poner una coma dentro de una etiqueta.

Lo mismo ocurre con los autores, pero usando un carácter diferente para el corte, un signo «&» en lugar de una coma. Por ejemplo, si la plantilla produce el valor Blogs, Joe&Posts, Susan, el libro acabará con dos autores, Blogs, Joe y Posts, Susan. Si la plantilla produce el valor Blogs, Joe;Posts, Susan, el libro tendrá un autor con un nombre peculiar.

Los paneles de conexiones afectan a los metadatos escritos en el libro cuando se guarda en disco o se escribe en un dispositivo. Los paneles de conexiones no afectan a los metadatos usados por las funciones Guardar en el disco Enviar al dispositivo para crear los nombres de archivo. En lugar de ello, los nombres de archivo se construyen usando las plantillas introducidas en la ventana de preferencias correspondiente.

Consejos:

  • Use la prueba de plantillas para probar plantillas. Añada esta función al menú contextual para libros en lea biblioteca o asígnele un atajo de teclado.

  • Las plantillas pueden usar otras plantillas haciendo referencia a columnas compuestas construidas con la plantilla deseada. También puede usar plantillas guardadas.

  • En un panel de conexiones, puede establecer un campo como vacío (o lo que sea equivalente a vacío) utilizando la plantilla especial {}. Esta plantilla siempre producirá un texto vacío.

  • La técnica descrita anteriormente para mostrar los números incluso si son cero funciona con el campo estándar series_index.

Referencia de funciones