Le langage de modèle calibre

Le langage de modèle de calibre est un langage spécifique à calibre utilisé dans l’ensemble de calibre pour des tâches telles que la spécification des chemins de fichiers, le formatage des valeurs et le calcul de la valeur des colonnes spécifiées par l’utilisateur. Exemples :

  • Spécifier la structure du dossier et les noms de fichiers lors de l’enregistrement des fichiers de la bibliothèque calibre sur le disque ou le lecteur de livres numériques.

  • Définir des règles pour l’ajout d’icônes et de couleurs à la liste de livres de calibre.

  • Définir les colonnes virtuelles qui contiennent des données provenant d’autres colonnes.

  • Recherche avancée dans la bibliothèque.

  • Recherche et remplacement avancé des métadonnées.

Le langage est construit autour de la notion de modèle, qui spécifie les métadonnées du livre à utiliser, les calculs sur ces métadonnées, et la façon dont elles doivent être formatées.

Modèles de base

Un modèle de base est constitué d’une ou plusieurs expression modèle. Une expression modèle consiste en du texte et des noms entre crochets ({}) qui sont remplacés par les métadonnées correspondantes du livre en cours de traitement. Par exemple, le modèle par défaut de calibre utilisé pour enregistrer des livres sur un périphérique comporte 4 expressions modèle:

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

Pour le livre « The Foundation » par « Isaac Asimov » cela donnera:

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

Les barres obliques ne sont pas des expressions modèle car elles se trouvent entre les {}. Un tel texte est laissé là où il apparaît. Par exemple, si le modèle est:

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

dès lors, pour « The Foundation », le modèle produit:

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

Une expression modèle peut accéder à toutes les métadonnées disponibles dans calibre, y compris les colonnes personnalisées (colonnes que vous créez vous-même), en utilisant le nom de recherche d’une colonne. Pour trouver le nom de recherche d’une colonne (parfois appelée champs), passez votre souris sur l’en-tête de la colonne dans la liste des livres de calibre. Les noms de recherche pour les colonnes personnalisées commencent toujours par #. Pour les colonnes de type série, il y a un champ supplémentaire appelé #lookup name_index qui est l’index de la série pour ce livre dans la série. Par exemple, si vous avez une colonne de série personnalisée nommée #messéries, il y aura également une colonne nommée #messéries_index. L’index de la colonne de série standard est nommé series_index.

En plus des champs standard basés sur des colonnes, vous pouvez également utiliser :

  • {formats} - Une liste des formats disponibles dans la bibliothèque calibre pour un livre

  • {identifiers:select(isbn)} - L’ISBN du livre

Si les métadonnées du champ pour un livre donné ne sont pas définies, le champ dans le modèle est remplacé par la chaîne vide (''). Par exemple, considérons le modèle suivant

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

Si le livre d’Asimov « Seconde Fondation » fait partie de la série « Fondation », alors le modèle produit

Asimov, Isaac/Foundation/Second Foundation 3

Si aucune série n’a été saisie pour le livre, le modèle produit

Asimov, Isaac/Second Foundation

Le processeur de modèles supprime automatiquement les barres obliques multiples et les espaces avant ou arrière.

Mise en forme avancée

Outre la substitution de métadonnées, les modèles peuvent inclure du texte supplémentaire de manière conditionnelle et contrôler le formatage des données substituées.

Comprenant conditionnellement le texte

Parfois, vous voulez que du texte n’apparaisse dans la sortie que si un champ n’est pas vide. Un cas courant est celui de series et series_index où vous voulez soit rien, soit les deux valeurs séparées par un trait d’union. calibre gère ce cas en utilisant une syntaxe spéciale de expression modèle.

Par exemple, et en utilisant l’exemple de Fondation ci-dessus, supposons que vous voulez que le modèle produise Fondation - 3 - Deuxième Fondation. Ce modèle produit ce résultat :

{series} - {series_index} - {title}

Cependant, si un livre n’a pas de série, le modèle produira - - le titre, ce qui n’est probablement pas ce que vous voulez. En général, les gens veulent que le résultat soit le titre sans les traits d’union superflus. Vous pouvez y parvenir en utilisant la syntaxe de modèle suivante :

{field:|prefix_text|suffix_text}

Cette expression modèle indique que si champ a la valeur XXXX, le résultat sera prefix_textXXXXXsuffix_text. Si champ est vide (n’a pas de valeur) alors le résultat sera la chaîne vide (rien) car le préfixe et le suffixe sont ignorés. Le préfixe et le suffixe peuvent contenir des blancs.

Ne pas utiliser de sous-modèles (`{ … }`) ou de fonctions (voir ci-dessous) dans le préfixe ou le suffixe.

En utilisant cette syntaxe, nous pouvons résoudre le problème de non-série ci-dessus avec le modèle

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

Les traits d’union ne seront inclus que si le livre possède un index de série, ce qui n’est le cas que si le livre possède une série. Si l’on reprend l’exemple de Fondation, le modèle produira Fondation - 1 - Deuxième Fondation.

Notes :

  • Vous devez inclure les deux points après le nom de la recherche si vous utilisez un préfixe ou un suffixe.

  • Vous devez utiliser soit aucun des caractères |, soit les deux. L’utilisation d’un seul caractère, comme dans {field:| - }, n’est pas autorisée.

  • Il est possible de ne fournir aucun texte pour le préfixe ou le suffixe, comme dans {série:|| - }. Le modèle {title:||} est le même que {title}.

Formatage

Supposons que vous vouliez que series_index soit formaté en trois chiffres avec des zéros en tête. Ceci fait l’affaire :

{series_index:0>3s} - Trois chiffres avec des zéros en tête

Pour des zéros qui suivent, utilisez:

{series_index:0>3s} - Trois chiffres avec des zéros qui suivent

Si vous utilisez des indices de série avec des valeurs fractionnées, par exemple 1.1, vous pouvez souhaiter que les points décimaux soient alignés. Par exemple, vous pouvez vouloir que les indices 1 et 2.5 apparaissent sous la forme 01.00 et 02.50 afin qu’ils soient triés correctement sur un périphérique qui effectue un tri lexical. Pour ce faire, utilisez :

{series_index:0>5.2f} - Cinq caractères composés de deux chiffres avec des zéros en tête, un point décimal, puis deux chiffres après le point décimal.

Si vous ne voulez que les deux premières lettres de la donnée, utilisez :

{author_sort :.2} - Seulement les deux premières lettres du nom de tri de l’auteur

Une grande partie du formatage du langage de modèle de calibre provient de Python. Pour plus de détails sur la syntaxe de ces opérations de formatage avancées, voir la documentation Python <https://docs.python.org/3/library/string.html#formatstrings>

Utilisation de modèles pour définir des colonnes personnalisées

Les modèles peuvent être utilisés pour afficher des informations qui ne sont pas dans les métadonnées de calibre, ou pour afficher les métadonnées différemment du format normal de calibre. Par exemple, vous pourriez vouloir afficher le ISBN, un champ que calibre n’affiche pas. Pour cela, vous pouvez créer une colonne personnalisée de type Colonne construite à partir d’autres colonnes (appelée ci-après colonnes composites) et fournir un modèle pour générer le texte affiché. La colonne affichera le résultat de l’évaluation du modèle. Par exemple, pour afficher l’ISBN, créez la colonne et entrez « identifiers:select(isbn)} » dans la champ du modèle. Pour afficher une colonne contenant les valeurs de deux colonnes personnalisées de séries, séparées par une virgule, utilisez {#series1:||,}{#series2}.

Les colonnes composites peuvent utiliser n’importe quelle option modèle, y compris le formatage.

Remarque : Vous ne pouvez pas modifier les données affichées dans une colonne composite. Vous devez plutôt modifier les colonnes sources. Si vous modifiez une colonne composite, par exemple en double-cliquant dessus, calibre ouvrira le modèle à modifier, et non les données sous-jacentes.

Modèles et tableaux de connexions

Les tableaux de connexions sont utilisés pour modifier les métadonnées écrites dans les livres pendant l’envoi à une liseuse et les opérations de sauvegarde sur le disque. Le tableau de connexion vous permet de spécifier pour un modèle de lecteur précis quelles données à insérer dans les métadonnées du livre. Vous pouvez utiliser les tableaux de connexions pour modifier les champs suivants : authors, author_sort, language, publisher, tags, title, title_sort. Cette fonctionnalité aide ceux qui veulent utiliser les différentes métadonnées des livres pour contrôler le tri ou l’affichage des livres sur leurs périphériques.

Lorsque vous créez un tableau de connexion, vous spécifiez le format et le périphérique pour lequel le tableau de connexion doit être utilisé. Un périphérique spécial est procuré, save_to_disk qui est utilisé lors de la sauvegarde de formats (en opposition à les envoyer vers le périphérique). Une fois que vous avez choisi le format et le périphérique, vous choisissez les champs de métadonnées à modifier, indiquez le modèle à appliquer pour fournir les nouvelles valeurs. Ces modèles sont reliés à leurs champs de destination, d’où le nom de tableau de connexions. Vous pouvez bien sûr utiliser des colonnes composites dans ces modèles.

Les tableaux de connexions sont assez flexibles et peuvent être écrits en mode fonction unique, en mode programme modèle, en mode programme général ou en mode modèle Python.

Quand un tableau de connexion doit s’appliquer (Serveur de contenu, sauvegarde sur disque ou envoyer au périphérique), calibre recherche les tableau de connexions définis et celui qui est correct pour le format donné et le périphérique. Par exemple, pour trouver le tableau de connexion approprié pour un livre EPUB envoyé à un périphérique ANDROID, calibre recherche dans les tableaux de connexion dans l’ordre de recherche suivant :

  • un tableau de connexion avec une correspondance exacte sur le format et le périphérique, par ex., EPUB et ANDROID

  • un tableau de connexion avec une correspondance exacte sur le format et le choix spécial n'importe quel périphérique, par ex., EPUB et n'importe quel périphérique

  • un tableau de connexion avec le choix spécial n'importe quel format et une correspondance exacte sur le périphérique, par ex., n'importe quel format et ANDROID

  • un tableau de conversion avec n'importe quel format et n'importe quel périphérique

Les étiquettes et les champs auteur ont un traitement spécial, parce que ces deux champs peuvent contenir plusieurs données. Un livre peut avoir plusieurs étiquettes et plusieurs auteurs. Lorsque vous spécifiez que l’un de ces deux champs doit être modifié, le résultat du modèle est examiné pour voir s’il y a plus d’un élément dedans. Pour les étiquettes, le résultat est découpé partout où calibre trouve une virgule. Par exemple, si le modèle produit les valeurs Thriller, Horreur, alors ke résultat sera deux étiquettes, Thriller et Horreur. Il n’est pas possible de mettre une virgule au milieu d’une étiquette.

La même chose se produit pour les auteurs, mais en utilisant un caractère différent comme séparateur, le & (esperluette) au lieu d’une virgule. Par exemple, si le modèle produit la valeur Blogs, Joe&Posts, Susan, alors le livre finira avec deux auteurs Blogs, Joe et Posts, Susan. Si le modèle produit la valeur Blogs, Joe;Posts, Susan, alors ce livre aura un auteur avec un nom assez étrange.

Les tableaux de connexions affectent les métadonnées écrites dans le livre quand il est sauvegardé sur le disque ou copié sur le périphérique. Les tableaux de connexions n’affecte pas les métadonnées utilisées par Enregistrer sur le disque et Envoyer au périphérique. A la place, les noms de fichiers sont construits en utilisant les modèles entrés dans la fenêtre de préférence appropriée.

Utilisation des fonctions dans les modèles - Mode de fonctionnement unique

Supposons que vous vouliez afficher la valeur d’un champ en casse majuscules alors que ce champ est normalement en casse titre. Vous pouvez le faire en utilisant les fonctions de modèle. Par exemple, pour afficher le titre en casse majuscules, utilisez la fonction uppercase, comme dans {title:uppercase()}. Pour l’afficher en casse titre, utilisez la fonction {title:titlecase()}.

Les fonctions sont placées dans la partie format du modèle, après le : et avant le premier | ou le } de fermeture si aucun préfixe/suffixe n’est utilisé. Si vous avez à la fois une référence de format et de fonction, la fonction vient après un deuxième :. Les fonctions renvoient la valeur de la colonne spécifiée dans le modèle, convenablement modifiée.

La syntaxe pour utiliser les fonctions est l’une des suivantes

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

Les noms de fonctions doivent toujours être suivis de parenthèses ouvrantes et fermantes. Certaines fonctions nécessitent des valeurs supplémentaires (arguments), qui sont placées à l’intérieur des parenthèses. Les arguments sont séparés par des virgules. Les virgules Littérales (les virgules en tant que texte, et non en tant que séparateurs d’arguments) doivent être précédées d’une barre oblique inversée (\) . Le dernier (ou le seul) argument ne peut pas contenir de parenthèse fermante textuelle.

Les fonctions sont évaluées avant les spécifications de format et le préfixe/suffixe. Voir plus bas pour un exemple d’utilisation à la fois d’un format et d’une fonction.

Important : Si vous avez de l’expérience en programmation, veuillez noter que la syntaxe du Mode Fonction Unique n’est pas celle à laquelle vous vous attendez. Les chaînes de caractères ne sont pas citées et les espaces sont significatifs. Tous les arguments sont considérés comme des constantes ; il n’y a pas d’expressions.

N’utilisez pas les sous-modèles (`{ … }`) comme arguments de fonction. A la place, utilisez plutôt Mode Programme Modèle et Mode Programme Général.

Certaines fonctions nécessitent des expressions régulières. Dans le langage des modèles, la correspondance des expressions régulières est insensible à la casse.

Dans la documentation des fonctions ci-dessous, la notation [quelque chose]* signifie que quelque chose peut être répété zéro fois ou plus. La notation [quelque chose]+ signifie que quelque chose est répété une ou plusieurs fois (doit exister au moins une fois).

Les fonctions destinées à être utilisées en Mode Fonction Unique sont les suivantes :

  • capitalize() – renvoie la valeur avec la première lettre en majuscule et le reste en minuscule.

  • contains(pattern, text if match, text if not match) – vérifie si la valeur est couverte par l’expression régulière pattern. Renvoie text if match si le motif correspond à la valeur, sinon renvoie text if no match.

  • count(separator) – interprète la valeur comme une liste d’éléments séparés par le separator et retourne le nombre d’éléments dans la liste. La plupart des listes utilisent une virgule comme séparateur, mais authors utilise une esperluette (&). Exemples : {tags:count(,)}, {authors:count(&)}. Alias : count(), list_count()

  • format_number(template) – interprète la valeur comme un nombre et formate ce nombre en utilisant un modèle de formatage Python tel que {0:5.2f} ou {0 :,d}` ou ${0:5,.2f}. Le modèle de formatage doit commencer par {0: et se terminer par } comme dans les exemples ci-dessus. Exception : vous pouvez omettre le début « {0 : » et la fin « } » si le modèle de format ne contient qu’un format. Voir le langage des modèles et la documentation Python pour plus d’exemples. Renvoie la chaîne vide si le formatage échoue.

  • human_readable() – s’attend que la valeur soit un nombre et renvoie une chaîne représentant ce nombre en KB, MB, GB, etc.

  • ifempty(text) – si le champ n’est pas vide, renvoie la valeur du champ. Autrement renvoie text if empty.

  • in_list(separator, [ pattern, found_val, ]* not_found_val) – interprète la valeur comme une liste d’éléments séparés par le separator, en vérifiant le pattern pour chaque élément de la liste. Si le pattern correspond à un élément, il renvoie found_val, sinon il renvoie not_found_val. La paire pattern``et ``found_value peut être répétée autant de fois que souhaité, ce qui permet de renvoyer des valeurs différentes selon la valeur de l’élément. Les motifs sont vérifiés dans l’ordre, et la première correspondance est retournée.

  • language_strings(localize) – retourne les noms de langue pour les codes de langue passés en tant que valeur. Exemple : {languages:language_strings()}. Si localize est zéro, retourne les chaînes de caractères en anglais. Si localize est différent de zéro, retourne les chaînes de caractères dans la langue de la locale courante. Lang_codes est une liste séparée par des virgules.

  • list_item(index, separator) – interprète la valeur comme une liste d’éléments séparés par un separator, en retournant index'. Le premier élément est le numéro zéro. Le dernier élément a l’indice -1 comme dans list_item(-1,separator). Si l’élément n’est pas dans la liste, alors la chaîne vide est retournée.

  • lookup([ pattern, key, ]* else_key) – Les motifs seront comparés à la valeur dans l’ordre. Si un motif correspond, la valeur du champ nommé par key est retournée. Si aucun motif ne correspond, la valeur du champ nommé par else_key est retournée. Voir switch (ci-dessous).

  • lowercase() – renvoie la valeur du champ en minuscule.

  • rating_to_stars(use_half_stars) – Renvoie la note sous forme de chaîne de caractères étoilés (). La valeur doit être un nombre entre 0 et 5. Définissez use_half_stars à 1 si vous voulez des caractères de demi-étoile pour les nombres fractionnés disponibles avec les colonnes d’évaluation personnalisées.

  • re(pattern, replacement) – retourne la valeur après application de l’expression régulière. Toutes les instances de pattern dans la valeur sont remplacées par replacement. Le langage des modèles utilise des Expressions régulières Python insensibles à la casse.

  • select(key) – interprète la valeur comme une liste d’éléments séparés par des virgules, chaque élément ayant la forme id:value (le format identifiant de calibre). La fonction trouve la première paire dont l’id est égal à key et renvoie la valeur correspondante. Si aucun id ne correspond, la fonction renvoie la chaîne vide.

  • shorten(left chars, middle text, right chars) – Renvoie une version raccourcie de la valeur, composée de left chars du début de la valeur, suivis de middle text, suivis de right chars de la fin de la valeur. Les « left chars » et les « right chars » doivent être des entiers non négatifs. Exemple : supposons que vous vouliez afficher le titre avec une longueur maximale de 15 caractères. Un modèle qui fait cela est {titre:shorten(9,-,5)}. Pour un livre dont le titre est Ancient English Laws in the Times of Ivanhoe, le résultat sera Ancient E-anhoe : les 9 premiers caractères du titre, un -, puis les 5 derniers caractères. Si la longueur de la valeur est inférieure à left chars + right chars + la longueur du middle text alors la valeur sera retournée inchangée. Par exemple, le titre Le Dôme ne sera pas modifié.

  • str_in_list(separator, [ string, found_val, ]+ not_found_val) – interprète la valeur comme une liste d’éléments séparés par le separator puis compare string à chaque valeur de la liste. string n’est pas une expression régulière. Si string est égal à n’importe quel élément (en ignorant la casse), alors il renvoie la found_val correspondante. Si string contient des separators, elle est également traitée comme une liste et chaque sous-valeur est vérifiée. Les paires string et found_value peuvent être répétées autant de fois que souhaité, ce qui permet de renvoyer des valeurs différentes selon la valeur de la chaîne. Si aucune des chaînes de caractères ne correspond, le système renvoie not_found_value. Les chaînes de caractères sont vérifiées dans l’ordre. La première correspondance est retournée.

  • subitems(start_index, end_index) – Cette fonction sépare les listes d’éléments hiérarchiques de type balise, comme les genres. Elle interprète la valeur comme une liste d’éléments de type balise séparés par des virgules, où chaque élément est une liste séparée par des points. Elle retourne une nouvelle liste faite en extrayant de chaque élément les composants de start_index à end_index, puis en fusionnant les résultats ensemble. Les doublons sont supprimés. Le premier sous-élément d’une liste séparée par un point a un indice de zéro. Si un index est négatif, il est compté à partir de la fin de la liste. Dans un cas particulier, un end_index de zéro est supposé être la longueur de la liste.

    Exemples :

    • Supposons une colonne #genre contenant A.B.C :

      • {#genre:subitems(0,1)} renvoie « A »

      • {#genre:subitems(0,2)} renvoie « A.B »

      • {#genre:subitems(1,0)} renvoie « B.C »

    • Supposons une colonne #genre contenant « A.B.C, D.E » :

      • {#genre:subitems(0,1)} renvoie « A, D »

      • {#genre:subitems(0,2)} renvoie « A.B, D.E »

  • sublist(start_index, end_index, separator) – interprète la valeur comme une liste d’éléments séparés par le separator, renvoyant une nouvelle liste composée des éléments de start_index à end_index. Le premier élément est le numéro zéro. Si un index est négatif, alors il compte à partir de la fin de la liste. Dans un cas spécial, un end_index de zéro est supposé être la longueur de la liste.

    Exemples en supposant que la colonne des étiquettes (qui est séparée par des virgules) contient « A, B ,C » :

    • {tags:sublist(0,1,\,)} renvoie « A »

    • {tags:sublist(-1,0,\,)} renvoie « C »

    • {tags:sublist(0,-1,\,)} renvoie « A, B »

  • swap_around_articles(separator) – renvoie la valeur avec les articles déplacés à la fin. La valeur peut être une liste, dans ce cas chaque article de la liste est traité. Si la valeur est une liste, vous devez fournir le séparateur. Si aucun séparateur n’est fourni, alors la valeur est traitée comme étant une valeur unique, et non une liste. Les articles sont ceux utilisés par calibre pour générer le title_sort.

  • swap_around_comma() – étant donné une valeur de la forme B, A, retourne A B. Ceci est très utile pour convertir des noms au format LN, FN en FN LN. S’il n’y a pas de virgule dans la valeur, la fonction retourne la valeur inchangée.

  • switch([pattern, value,]+ else_value) – pour chaque paire pattern, value, vérifie si la valeur correspond à l’expression régulière pattern et si oui, retourne la value associée. Si aucun pattern ne correspond, else_value est retourné. Vous pouvez avoir autant de couples pattern, value que vous le souhaitez. La première correspondance est retournée.

  • test(text if not empty, text if empty) – retourne text if not empty si la valeur n’est pas vide, sinon retourne text if empty.

  • titlecase() – renvoie la valeur du champ en casse titre.

  • transliterate() - Restitue une chaîne en alphabet latin représentant approximativement le son des mots de la chaîne source. Par exemple, si le champ source est Фёдор Миха́йлович Достоевский la fonction renverra Fiodor Mikhailovich Dostoievskii.”

  • uppercase() – renvoie la valeur du champ en majuscule.

Utilisation des fonctions et du formatage dans le même modèle

Supposons que vous ayez une colonne personnalisée de nombres entiers, ##myint, que vous voulez afficher avec des zéros en tête, comme dans 003. Une façon de le faire est d’utiliser le format 0>3s. Cependant, par défaut, si un nombre (entier ou flottant) est égal à zéro, la valeur est affichée sous la forme d’une chaîne vide, de sorte que les valeurs nulles produiront la chaîne vide, et non 000. Si vous voulez voir les valeurs 000, vous devez utiliser à la fois la chaîne de format et la fonction ifempty pour transformer la valeur vide en zéro. Le modèle serait

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

Notez que vous pouvez également utiliser le préfixe et le suffixe. Si vous voulez que le numéro apparaisse sous la forme [003] ou [000], utilisez alors le modèle

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

Mode Programme Général

Le Mode Programme Général (MPG) remplace les expressions modèles par un programme écrit dans le langage modèle. La syntaxe de ce langage est définie par la grammaire suivante

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 ]* | concatenate_expr
concatenate_expr::= compare_expr [ '&' compare_expr ]*
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 ')' | function_def
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 ]* ')'
function_def    ::= 'def' identifier '(' top_expression [ ',' top_expression ]* ')' ':'
                    expression_list 'fed'
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_list | for_range
for_list        ::= 'for' identifier 'in' list_expr
                    [ 'separator' separator_expr ] ':' expression_list 'rof'
for_range       ::= 'for' identifier 'in' range_expr ':' expression_list 'rof'
range_expr      ::= 'range' '(' [ start_expr ',' ] stop_expr
                    [ ',' step_expr [ ',' limit_expr ] ] ')'
list_expr       ::= top_expression
break_expr      ::= 'break'
continue_expr   ::= 'continue'
separator_expr  ::= top_expression
start_expr      ::= top_expression
stop_expr       ::= top_expression
step_expr       ::= top_expression
limit_expr      ::= top_expression

Notes :

  • une top_expression a toujours une valeur. La valeur d’une expression_list est la valeur de la dernière top_expression Par exemple, la valeur de la liste d’expressions 1;2;'foobar';3 est 3.

  • Dans un contexte logique, toute valeur non vide est True.

  • Dans un contexte logique, la valeur vide est False.

  • Les chaînes de caractères et les nombres peuvent être utilisés indifféremment. Par exemple, 10 et '10' sont la même chose.

  • Les commentaires sont des lignes commençant par le caractère « # ». Les commentaires commençant plus loin dans une ligne ne sont pas pris en charge.

Préséance de l’opérateur

L’ordre de préséance de l’opérateurs (ordre d’évaluation), du plus élevé (évalué en premier) au plus bas (évalué en dernier), est le suivant :

  • Appels de fonctions, constantes, expressions entre parenthèses, expressions d’instructions, expressions d’affectation, références de champs.

  • Les opérateurs unaires plus (+) et moins (-). Ces opérateurs s’évaluent de droite à gauche.

    Ces opérateurs et tous les autres opérateurs arithmétiques renvoient des entiers si l’expression donne une partie fractionnaire égale à zéro. Par exemple, si une expression renvoie 3.0, elle est transformée en 3.

  • Multiplier (*) et diviser (/). Ces opérateurs sont associatifs et s’évaluent de gauche à droite. Utilisez les parenthèses si vous souhaitez modifier l’ordre d’évaluation.

  • Additionner (+) et soustraire (-). Ces opérateurs sont associatifs et s’évaluent de gauche à droite.

  • Comparaisons de nombres et de chaînes de caractères. Ces opérateurs renvoient '1' si la comparaison réussit, sinon la chaîne vide (''). Les comparaisons ne sont pas associatives : a < b < c est une erreur de syntaxe.

  • Concaténation de chaînes de caractères (&). L’opérateur & renvoie une chaîne de caractères formée par la concaténation des expressions de gauche et de droite. Exemple : «  “aaa” & “bbb”`` renvoie «  “aaabbb”``. L’opérateur est associatif et s’évalue de gauche à droite.

  • Unaire non logique (!). Cet opérateur renvoie '1' si l’expression est fausse (évaluée à la chaîne vide), sinon ''.

  • L’opérateur logique et (&&). Cet opérateur renvoie “1” si les deux expressions de gauche et de droite sont vraies, ou la chaîne vide '' si l’une ou l’autre est fausse. Il est associatif, s’évalue de gauche à droite, et fait du court-circuitage.

  • Logique ou (||). Cet opérateur renvoie '1' si l’expression de gauche ou de droite est vraie, ou '' si les deux sont fausses. Il est associatif, s’évalue de gauche à droite, et fait du court-circuitage. C’est un or inclusif, qui renvoie « 1 » si les deux expressions de gauche et de droite sont vraies.

Références des champs

Un « field_reference » est évalué à la valeur du champ de métadonnées nommé par le nom de la consultation qui suit le « $ » ou le « $$ ». L’utilisation de $ équivaut à l’utilisation de la fonction field(). L’utilisation de $$ équivaut à l’utilisation de la fonction raw_field. Exemples

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

Expressions if

Les expressions If évaluent d’abord la condition. Si la condition est True (une valeur non vide), alors expression_list de la clause then est évaluée. Si elle est False, expression_list de la clause elif ou else est évaluée si elle est présente. Les parties if et else sont facultatives. Les mots if ``, ``then, elif ``, ``else et fi sont réservés ; vous ne pouvez pas les utiliser comme noms d’identifiants. Vous pouvez mettre des retours à la ligne et des espaces partout où cela a un sens. La condition est une top_expression et non une expression_list ; les points-virgules ne sont pas autorisés. Les expression_list sont des séquences de top_expressions séparées par des points-virgules. Une expression if renvoie le résultat de la dernière top_expressions de la top_expression évaluée, ou la chaîne vide si aucune liste d’expression n’a été évaluée.

Exemples:

* 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)

Exemple de if imbriqué:

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

Comme dit plus haut, un if produit une valeur. Cela signifie que tous les cas suivants sont équivalents

* 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

Comme dernier exemple, ce programme retourne la valeur de la colonne series si le livre a une série, sinon la valeur de la colonne title

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

Expressions for

L’expression for itère sur une liste de valeurs, en les traitant une par une. L’expression « list_expression » doit être évaluée soit par un nom de champ de métadonnées, par exemple tags ou #genre, soit par une liste de valeurs. Si le résultat est un lookup name valide, alors la valeur du champ est récupérée et le séparateur spécifié pour ce type de champ est utilisé. Si le résultat n’est pas un nom de référence valide, il est supposé être une liste de valeurs. La liste est supposée être séparée par des virgules, sauf si le mot-clé optionnel separator est fourni, auquel cas les valeurs de la liste doivent être séparées par le résultat de l’évaluation de l’expression separator_expr. Un séparateur ne peut pas être utilisé si la liste est générée par range(). Chaque valeur de la liste est assignée à la variable spécifiée puis la expression_list est évaluée. Vous pouvez utiliser break pour sortir de la boucle, et continue pour revenir au début de la boucle pour la prochaine itération.

Exemple : Ce modèle supprime le premier nom hiérarchique pour chaque valeur dans le genre (#genre), en construisant une liste avec les nouveaux noms

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

Si le Genre original est Histoire.Militaire, Science Fiction.Histoire alternative, Lisez-moi, alors le modèle renvoie Militaire, Histoire alternative, Lisez-moi. Vous pouvez utiliser ce modèle dans le calibre Modifier les métadonnées par lot  →  Rechercher & remplacer avec Rechercher après défini à modèe pour supprimer le premier niveau de la hiérarchie et attribuer la valeur résultante à Genre.

Note : la dernière ligne du modèle, new_tags, n’est pas strictement nécessaire dans ce cas car for renvoie la valeur de la dernière top_expression de la liste d’expressions. La valeur d’une affectation est la valeur de son expression, donc la valeur de l’instruction for est ce qui a été affecté à new_tags.

Définition de la fonction

Si vous avez du code dans un modèle qui se répète, vous pouvez mettre ce code dans une fonction locale. Le mot clé « def » commence la définition. Il est suivi par le nom de la fonction, la liste des arguments, puis le code de la fonction. La définition de la fonction se termine par le mot-clé ``fed””.

Les arguments sont positionnels. Lorsqu’une fonction est appelée, les arguments fournis sont comparés de gauche à droite aux paramètres définis, la valeur de l’argument étant attribuée au paramètre. C’est une erreur de fournir plus d’arguments que de paramètres définis. Les paramètres peuvent avoir des valeurs par défaut, comme « a = 25 ». Si un argument n’est pas fourni pour ce paramètre, alors la valeur par défaut est utilisée, sinon le paramètre est défini par la chaîne vide.

L’instruction return peut être utilisée dans une fonction locale.

Une fonction doit être définie avant de pouvoir être utilisée.

Exemple : Ce modèle calcule une durée approximative en années, mois et jours à partir d’un nombre de jours. La fonction to_plural() met en forme les valeurs calculées. Notez que l’exemple utilise également l’opérateur &:

program:
      days = 2112;
      years = floor(days/360);
      months = floor(mod(days, 360)/30);
      days = days - ((years*360) + (months * 30));

      def to_plural(v, str):
              if v == 0 then return '' fi;
              return v & ' ' & (if v == 1 then str else str & 's' fi) & ' '
      fed;

      to_plural(years, 'year') & to_plural(months, 'month') & to_plural(days,'day')

Opérateurs relationnels

Les opérateurs relationnels renvoient '1' si la comparaison est vraie, sinon la chaîne vide (“”).

Il existe deux formes d’opérateurs relationnels : les comparaisons de chaînes de caractères et les comparaisons numériques.

Les comparaisons de chaînes de caractères effectuent une comparaison insensible à la casse en utilisant l’ordre lexical. Les opérateurs de comparaison de chaînes de caractères pris en charge sont ==, !=, <, <=, >, >=, in, et inlist. Pour l’opérateur in, le résultat de l’expression de gauche est interprété comme un motif d’expression régulière. L’opérateur in est True si la valeur de l’expression régulière de gauche correspond à la valeur de l’expression de droite. L’opérateur inlist est vrai si l’expression régulière de gauche correspond à l’un des éléments de la liste de droite, les éléments de la liste étant séparés par des virgules. Les correspondances sont insensibles à la casse.

Les opérateurs de comparaison numérique sont ==#, !=#, <#, <=#, >#, >=#. Les expressions de gauche et de droite doivent être évaluées par des valeurs numériques, à deux exceptions près : la chaîne de caractères « None » (champ indéfini) et la chaîne de caractères vide sont évaluées par la valeur zéro.

Exemples :

  • program:field('series') == 'foo' renvoie '1' si la série du livre est “foo”, sinon ''.

  • Program: 'f.o' in field('series') renvoie “1”` si la série du livre correspond à l’expression régulière f.o (par exemple, foo, Off Onyx, etc.), sinon ''.

  • Program: 'science' inlist field('#genre') renvoie '1' si l’un des genres du livre correspond à l’expression régulière science, par exemple, Science, Histoire de la science, Science Fiction etc., sinon ''.

  • Program: '^science$' inlist field('#genre') renvoie “1”` si l’un des genres du livre correspond exactement à l’expression régulière ^science$, par exemple, Science. Les genres Histoire des sciences et Science Fiction ne correspondent pas. S’il n’y a pas de correspondance, elle renvoie ''.

  • Program: if field('series') != 'foo' then 'bar' else 'mumble' fi renvoie 'bar' si la série du livre n’est pas foo. Sinon, renvoie mumble.

  • Program: if field('series') == 'foo' || field('series') == '1632' then 'yes' else 'no' fi renvoie 'yes' si séries existe soit 'foo' soit '1632', sinon “no”`.

  • program: if '^(foo|1632)$' in field('series') then 'yes' else 'no' fi renvoie 'yes' si la série existe soit 'foo' ou '1632', sinon 'no'.

  • program: if '11' > '2' then 'yes' else 'no' fi renvoie `”no”`` parce que l’opérateur > fait une comparaison lexicale.

  • Program: if 11 ># 2 then 'yes' else 'no' fi renvoie 'yes' parce que l’opérateur ># effectue une comparaison numérique.

Fonctions supplémentaires disponibles

Les fonctions suivantes sont disponibles en plus de celles décrites dans Mode fonction unique.

Dans MPG, les fonctions décrites dans Mode Fonction Simple requièrent toutes un premier paramètre supplémentaire spécifiant la valeur sur laquelle opérer. Tous les paramètres sont des listes d’expressions (voir la grammaire ci-dessus).

  • add(x [, y]*) – renvoie la somme de ses arguments. Lance une exception si un argument n’est pas un nombre. Dans la plupart des cas, vous pouvez utiliser l’opérateur + à la place de cette fonction.

  • and(value [, value]*) – retourne la chaîne « 1 » si toutes les valeurs ne sont pas vides, sinon retourne la chaîne vide. Vous pouvez avoir autant de valeurs que vous le souhaitez. Dans la plupart des cas, vous pouvez utiliser l’opérateur && à la place de cette fonction. Une raison de ne pas remplacer and par && est que le court-circuitage peut modifier les résultats à cause d’effets secondaires. Par exemple, et(a='',b=5) fera toujours les deux affectations, alors que l’opérateur && ne fera pas la seconde.

  • assign(id, val) – affecte val à id, puis retourne val. id doit être un identifiant, pas une expression. Dans la plupart des cas, vous pouvez utiliser l’opérateur = à la place de cette fonction.

  • approximate_formats() – renvoie une liste, séparée par des virgules, des formats associés au livre. Il n’y a aucune garantie que la liste soit correcte, bien qu’elle le soit probablement. Cette fonction et d’autres fonctions à zéro paramètre peuvent être appelées en mode programme modèle (voir ci-dessous) en utilisant le modèle {:'approximate_formats()'}. Notez que les noms de formats résultants sont toujours en majuscules, comme dans EPUB. La fonction approximate_formats() est nettement plus rapide que les fonctions formats_... présentées ci-dessous.

  • author_links(val_separator, pair_separator) – renvoie une chaîne contenant une liste d’auteurs et les valeurs des liens de ces auteurs sous la forme

    author1 val_separator author1_link pair_separator author2 val_separator author2_link etc.
    

    Un auteur est séparé de sa valeur de lien par la chaîne val_separator sans espaces ajoutés. Les paires author:linkvalue sont séparées par la chaîne de caractères pair_separator, sans espaces ajoutés. C’est à vous de choisir des chaînes de séparation qui n’apparaissent pas dans les noms d’auteurs ou les liens. Un auteur est inclus même si le lien de l’auteur est vide.

  • author_sorts(val_separator) – renvoie une chaîne contenant une liste des valeurs de tri de l’auteur pour les auteurs du livre. Le tri est celui des métadonnées auteur (différente de l’author_sort dans les livres). La liste renvoyée a la forme author sort 1 val_separator author sort 2 etc. Les valeurs de tri auteur dans cette liste sont dans le même ordre que les auteurs du livre. Si vous voulez les espaces autour du val_separator incluez les alors dans la chaîne val_separator.

  • book_count(query, use_vl) – renvoie le nombre de livres trouvés en cherchant pour query. Si use_vl est 0 (zéro) alors les bibliothèques virtuelles sont ignorées. Cette fonction et son pendant book_values() sont particulièrement utiles dans les recherches de modèles, en supportant les recherches qui combinent les informations de plusieurs livres, comme la recherche de séries avec un seul livre. Elle ne peut pas être utilisée dans les colonnes composites, sauf si le paramètre « allow_template_database_functions_in_composites » a la valeur True. Elle ne peut être utilisée que dans l’interface graphique.

    Par exemple, ce modèle de recherche utilise cette fonction et son pendant pour trouver toutes les séries ne comportant qu’un seul livre :

    1. Définir un modèle enregistré (en utilisant Préférences → Avancé → Modèles de fonctions) nommé série_uniquement_un_livre (le nom est arbitraire). Le modèle est

      program:
          vals = globals(vals='');
          if !vals then
              all_series = book_values('series', 'series:true', ',', 0);
              for series in all_series:
                  if book_count('series:="' & series & '"', 0) == 1 then
                      vals = list_join(',', vals, ',', series, ',')
                  fi
              rof;
              set_globals(vals)
          fi;
          str_in_list(vals, ',', $series, 1, '')
      

    La première fois que le modèle s’exécute (le premier livre vérifié), il enregistre les résultats des recherches dans la base de données dans une variable de modèle « globale » appelée « vals ». Ces résultats sont utilisés pour vérifier les livres suivants sans avoir à refaire les recherches.

    1. Utiliser le modèle enregistré dans une recherche de modèle

      template:"program: series_only_one_book()#@#:n:1"
      

    L’utilisation d’un modèle stocké au lieu de mettre le modèle dans la recherche élimine les problèmes causés par l’obligation d’échapper les guillemets dans les expressions de recherche.

  • book_values(column, query, sep, use_vl) – renvoie une liste des valeurs uniques contenues dans la colonne column (un nom de recherche), séparées par sep, dans les livres trouvés en recherchant query. Si use_vl est 0 (zéro), alors les bibliothèques virtuelles sont ignorées. Cette fonction et son pendant book_count() sont particulièrement utiles dans les recherches de modèles, en supportant les recherches qui combinent les informations de plusieurs livres, comme la recherche de séries avec un seul livre. Elle ne peut pas être utilisée dans des colonnes composites, sauf si le paramètre « allow_template_database_functions_in_composites » a la valeur True. Elle ne peut être utilisée que dans l’interface graphique.

  • booksize() – renvoie la valeur du champ “size” de calibre. Renvoie “” s’il n’y a pas de formats.

  • check_yes_no(field_name, is_undefined, is_false, is_true) – vérifie si la valeur du champ oui/non nommé par le nom de la référence externe field_name est l’une des valeurs spécifiées par les paramètres, renvoyant 'yes' si une correspondance est trouvée sinon renvoyant la chaîne vide. Définissez le paramètre is_undefined, is_false ou is_true à 1 (le nombre) pour vérifier cette condition, sinon définissez-le à 0. Exemple :

    check_yes_no("#bool", 1, 0, 1) renvoie 'Yes' si le champ oui/non #bool est soit True soit non-défini (ni True ni False).

    Plus d’un élément parmi «  is_undefined « , «  is_false «  ou «  is_true «  peut être mis à 1.

  • ceiling(x) – renvoie le plus petit entier supérieur ou égal à x. Envoie une exception si x n’est pas un nombre.

  • character(character_name) – renvoie le caractère désigné par character_name. Par exemple, character('newline') renvoie un caractère de nouvelle ligne ('\n'). Les noms de caractères pris en charge sont newline, return, tab, et backslash.

  • cmp(x, y, lt, eq, gt) – compare x et y après les avoir convertis en nombres. Renvoie lt si x <# y, eq si x ==# y, sinon gt. Cette fonction peut généralement être remplacée par l’un des opérateurs de comparaison numérique (==#, <#, >#, etc).

  • connected_device_name(storage_location_key) – si un périphérique est connecté alors retourne le nom du périphérique, sinon retourne la chaîne vide. Chaque emplacement de stockage sur un périphérique peut avoir un nom différent. Les noms storage_location_key sont 'main', 'carda' et 'cardb'. Cette fonction ne fonctionne que dans l’interface graphique.

  • connected_device_uuid(storage_location_key) – si un périphérique est connecté alors retourne l’uuid du périphérique (id unique), sinon retourne la chaîne vide. Chaque emplacement de stockage sur un périphérique a un uuid différent. Les noms storage_location_key sont 'main', 'carda' et 'cardb'. Cette fonction ne fonctionne que dans l’interface graphique.

  • current_library_name() – renvoie le dernier nom sur le chemin de la bibliothèque calibre actuelle.

  • current_library_path() – renvoie le chemin complet vers la bibliothèque calibre actuelle.

  • current_virtual_library_name() – retourne le nom de la bibliothèque virtuelle actuelle s’il y en a une, sinon la chaîne vide. La casse du nom de la bibliothèque est préservée. Exemple : « program:current_virtual_library_name() ». Cette fonction ne fonctionne que dans l’Interface Graphique.

  • date_arithmetic(date, calc_spec, fmt) – Calcule une nouvelle date à partir de date en utilisant calc_spec. Retourne la nouvelle date formatée selon l’option fmt : si elle n’est pas fournie, le résultat sera au format ISO. calc_spec est une chaîne de caractères formée par la concaténation de paires de vW (valueWhat) où v est un nombre éventuellement négatif et W est l’une des lettres suivantes :

    • s: ajoute v secondes à date

    • m: ajoute v minutes à date

    • h: ajoute v heures à date

    • d: ajoute v jours à date

    • w: ajoute v semaines à date

    • y: ajoute v années à date, où une année compte 365 jours.

    Exemple : '1s3d-1m' ajoutera 1 seconde, ajoutera 3 jours, et soustraira 1 minute de date.

  • days_between(date1, date2) – renvoie le nombre de jours entre date1 et date2. Le nombre est positif si date1 est plus grand que date2, sinon négatif. Si date1 ou date2 ne sont pas des dates, la fonction renvoie une chaîne vide.

  • divide(x, y) – renvoie x / y. Lance une exception si x ou y ne sont pas des nombres. Cette fonction peut généralement être remplacée par l’opérateur /.

  • eval(string) – évalue la chaîne comme un programme, en passant les variables locales. Cela permet d’utiliser le processeur de modèles pour construire des résultats complexes à partir de variables locales. En Mode Modèle de Programme, comme les caractères { et } sont interprétés avant l’évaluation du modèle, vous devez utiliser [[] pour le caractère { et ]] pour le caractère }. Ils sont convertis automatiquement. Notez également que les préfixes et les suffixes (la syntaxe |prefix|suffix) ne peuvent pas être utilisés dans l’argument de cette fonction lors de l’utilisation de Mode Modèle de Programme.

  • extra_file_size(file_name) – retourne la taille en octets du fichier supplémentaire file_name dans le dossier data/ du livre s’il existe, sinon -1. Voir aussi les fonctions has_extra_files(), extra_file_names() et extra_file_modtime(). Cette fonction ne peut être utilisée que dans l’interface graphique.

  • extra_file_modtime(file_name, format_string) – retourne l’heure de modification du fichier supplémentaire file_name dans le dossier data/ du livre s’il existe, sinon -1. La date de modification est formatée selon format_spec (voir format_date() pour plus de détails). Si format_spec est une chaîne vide, elle retourne l’heure de modification sous la forme d’un nombre de secondes en virgule flottante depuis Epoch. Voir aussi les fonctions has_extra_files(), extra_file_names() et extra_file_size(). L’Epoch dépend du système d’exploitation. Cette fonction ne peut être utilisée que dans l’interface graphique.

  • extra_file_names(sep [, pattern]) – retourne une liste séparée de sep de fichiers supplémentaires dans le dossier data/ du livre. Si le paramètre optionnel pattern, une expression régulière, est fourni, alors la liste est filtrée sur les fichiers qui correspondent à pattern. La correspondance est insensible à la casse. Voir aussi les fonctions has_extra_files(), extra_file_modtime() et extra_file_size(). Cette fonction ne peut être utilisée que dans l’interface graphique.

  • field(lookup_name) – renvoie la valeur du champ de métadonnées avec le nom de recherche lookup_name.

  • field_exists(field_name) – vérifie si un champ (colonne) avec le nom de recherche field_name existe, retournant “1”` si c’est le cas et la chaîne vide si non.

  • finish_formatting(val, fmt, prefix, suffix) – applique le format, le préfixe et le suffixe à une valeur de la même manière que dans un modèle comme {series_index:05.2f| - |- }. Cette fonction est fournie pour faciliter la conversion des modèles complexes single-function- ou modèles template-program-mode en modèles MGP. Par exemple, le programme suivant produit la même sortie que le modèle ci-dessus

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

    Un autre exemple: pour le modèle {series:re(([^\s])[^\s]+(\s|$),\1)}{series_index:0>2s| - | - }{title} utilisez:

    program:
      strcat(
        re(field('series'), '([^\s])[^\s]+(\s|$)', '\1'),
           finish_formatting(field('series_index'), '0>2s', ' - ', ' - '),
           field('title')
      )
    
  • first_matching_cmp(val, [ cmp, result, ]* else_result) – compare val < cmp en séquence, en retournant le résultat associé à la première comparaison qui réussit. Retourne else_result si aucune comparaison ne réussit. Exemple

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

    renvoie "grand". Le même exemple avec une première valeur de 16 renvoie "géant".

  • first_non_empty(value [, value]*) – retourne la première valeur non vide. Si toutes les valeurs sont vides, alors la chaîne vide est retournée. Vous pouvez avoir autant de valeurs que vous voulez.

  • floor(x) – renvoie le plus grand entier inférieur ou égal à x. Envoie une exception si x n’est pas un nombre.

  • format_date(val, format_string) – formate la valeur, qui doit être une chaîne date, en utilisant format_string, retournant une chaîne. Les codes de formatage sont:

    • d : le jour sous la forme d’un nombre sans zéro initial (1 à 31)

    • dd : le jour sous la forme d’un nombre avec un zéro initial (1 à 31)

    • ddd : le nom abrégé du jour localisé (par exemple de « Lun » à « Dim »).

    • dddd : le nom long du jour localisé (par exemple de « lundi » à « dimanche »).

    • M : le mois sous la forme d’un nombre sans zéro initial (1 à 12).

    • MM : le mois sous la forme d’un nombre avec un zéro initial (1 à 12).

    • MMM : le nom abrégé du mois localisé (par exemple de « Jan » à « Déc »).

    • MMMM : le nom long du mois localisé (par exemple de « janvier » à « décembre »).

    • yy : l’année sous la forme d’un nombre à deux chiffres (00 à 99).

    • yyyy : l’année sous la forme d’un nombre à quatre chiffres.

    • h : les heures sans le premier 0 (0 à 11 ou 0 à 23, selon am/pm)

    • hh : les heures avec le premier 0 (00 à 11 ou 00 à 23, selon am/pm)

    • m : les minutes sans le premier 0 (0 à 59)

    • mm : les minutes avec le premier 0 (00 à 59)

    • s : les secondes sans le premier 0 (0 à 59)

    • ss : les secondes avec un 0 en tête (00 à 59)

    • ap : utilise une horloge de 12 heures au lieu d’une horloge de 24 heures, avec “ap” remplacé par la chaîne localisée pour am ou pm.

    • AP : utilise une horloge de 12 heures au lieu d’une horloge de 24 heures, avec “AP” remplacé par la chaîne localisée pour AM ou PM.

    • iso : la date avec l’heure et le fuseau horaire. Ce doit être le seul format présent.

    • to_number : convertit la date et l’heure en un nombre à virgule flottante (un timestamp)

    • from_number : convertit un nombre à virgule flottante (un timestamp) en une date formatée iso. Si vous souhaitez un format de date différent, ajoutez la chaîne de formatage souhaitée après from_number et un deux-points (:). Exemple : from_number:MMM dd yyyy.

    Vous pouvez obtenir des résultats inattendus si la date que vous formatez contient des noms de mois localisés, ce qui peut se produire si vous avez modifié les ajustements de format de date pour qu’ils contiennent MMMM. Dans ce cas, au lieu d’utiliser la fonction field() comme dans

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

    utiliser la fonction raw_field() comme dans

    format_date(raw_field('pubdate'), 'yyyy')
    
  • format_date_field(field_name, format_string) – formate la valeur du champ field_name, qui doit être le nom d’un champ date, standard ou personnalisé. Voir format_date() pour les codes de formatage. Cette fonction est beaucoup plus rapide que format_date et doit être utilisée lorsque vous formatez la valeur d’un champ (colonne). Elle ne peut pas être utilisée pour des dates calculées ou des dates dans des variables de type chaîne. Exemples :

    format_date_field('pubdate', 'yyyy.MM.dd')
    format_date_field('#date_read', 'MMM dd, yyyy')
    
  • formats_modtimes(date_format_string) – renvoie une liste séparée par des virgules d’éléments séparés par des deux points FMT:DATE représentant les heures de modification des formats d’un livre. Le paramètre date_format_string spécifie comment la date doit être formatée. Voir la fonction format_date() pour plus de détails. Vous pouvez utiliser la fonction select pour obtenir l’heure de modification d’un format spécifique. Notez que les noms de format sont toujours en majuscules, comme dans EPUB.

  • formats_paths() – retourne une liste d’éléments séparés par des virgules et des deux-points FMT:PATH donnant le chemin complet vers les formats d’un livre. Vous pouvez utiliser la fonction select pour obtenir le chemin d’accès à un format spécifique. Notez que les noms de format sont toujours en majuscules, comme dans EPUB.

  • formats_sizes() – renvoie une liste d’éléments FMT:SIZE séparés par des virgules, donnant les tailles en octets des formats d’un livre. Vous pouvez utiliser la fonction select pour obtenir la taille d’un format spécifique. Notez que les noms de format sont toujours en majuscules, comme dans EPUB.

  • fractional_part(x) – renvoie la valeur après la virgule. Par exemple, fractional_part(3.14) renvoie 0.14. Envoie une exception si x n’est pas un nombre.

  • get_link(field_name, field_value) – récupère le lien pour le champ field_name avec la valeur field_value. S’il n’y a pas de lien attaché, il renvoie “”. Exemple :

  • Ce qui suit renvoie le lien attaché à l’étiquette Fiction.

    get_link('tags', 'Fiction')
    
  • Ce modèle crée une liste de liens pour tous les tags associés à un livre sous la forme valeur:lien,  :

    program:
     ans = '';
     for t in $tags:
         l = get_link('tags', t);
         if l then
             ans = list_join(', ', ans, ',', t & ':' & get_link('tags', t), ',')
         fi
     rof;
     ans
    
  • has_cover() – retourne 'Yes' si le livre a une couverture, sinon la chaîne vide.

  • has_extra_files([pattern]) – retourne le nombre de fichiers supplémentaires, sinon “” (la chaîne vide). Si le paramètre optionnel pattern (une expression régulière) est fourni, alors la liste est filtrée sur les fichiers qui correspondent à pattern avant que les fichiers ne soient comptés. La correspondance est insensible à la casse. Voir aussi les fonctions extra_file_names(), extra_file_size() et extra_file_modtime(). Cette fonction ne peut être utilisée que dans l’interface graphique.

  • identifier_in_list(val, id_name [, found_val, not_found_val]) – traite val comme une liste d’identifiants séparés par des virgules. Un identifiant a le format id_name:value. Le paramètre id_name est le texte de l’identifiant à rechercher, soit id_name soit id_name:regexp. Dans le premier cas, la recherche s’effectue s’il existe un identifiant correspondant à ce nom d’utilisateur. Dans le second cas, la recherche se fait si le id_name correspond à un identifiant et que l’expression rationnelle correspond à la valeur de l’identifiant. Si found_val et not_found_val sont fournis, alors s’il y a une correspondance, il retourne found_val, sinon il retourne not_found_val. Si found_val et not_found_val ne sont pas fournis, alors s’il y a une correspondance, alors la paire identifier:value est retournée, sinon la chaîne vide (“”).

  • is_marked() – vérifie si le livre est marqué dans calibre. S’il l’est, retourne la valeur de la marque, soit true' (minuscule), soit une liste de marques nommées, séparées par des virgules.. Si le livre n’est pas marqué, retourne " (chaîne vide). Cette fonction ne fonctionne que dans l’interface graphique.

  • language_codes(lang_strings) – retourne les codes de langue pour les noms de langue passés dans lang_strings. Les chaînes de caractères doivent être dans la langue de la locale courante. Lang_strings est une liste séparée par des virgules.

  • list_contains(value, separator, [ pattern, found_val, ]* not_found_val) – (Alias de in_list) Interprétant la valeur comme une liste d’éléments séparés par le separator, évalue le pattern par rapport à chaque valeur de la liste. Si le pattern correspond à une valeur, il renvoie found_val, sinon il renvoie not_found_val. Le pattern et la found_value peuvent être répétés autant de fois que vous le souhaitez, ce qui permet de renvoyer différentes valeurs en fonction de la recherche. Les motifs sont vérifiés dans l’ordre. La première correspondance est retournée. Alias : in_list(), list_contains().

  • list_count(value, separator) – interprète value comme une liste d’éléments séparés par separator, et retourne le nombre d’éléments dans la liste. Alias : count(), list_count()

  • list_count_matching(list, pattern, separator) – interprète list comme une liste d’éléments séparés par separator, en retournant le nombre d’éléments dans la liste qui correspondent à l’expression régulière pattern. Alias : list_count_matching(), count_matching()

  • list_difference(list1, list2, separator) – restitue une liste en supprimant de list1 tout élément trouvé dans list2 ``en utilisant une comparaison insensible à la casse. Les éléments dans ``list1 et list2 sont séparés par le séparateur, comme le sont les éléments dans la liste restituée.

  • list_equals(list1, sep1, list2, sep2, yes_val, no_val) –retourne yes_val si list1 et list2 contiennent les mêmes éléments, sinon renvoie no_val. Les éléments sont déterminés en éclatant chaque liste à l’aide du séparateur approprié (sep1 ou sep2). L’ordre des éléments dans la liste n’est pas pris en compte. La comparaison est insensible à la casse.

  • list_intersection(list1, list2, separator) – retourne une liste faite en retirant de list1 tout élément non trouvé dans list2, en utilisant une comparaison insensible à la casse. Les éléments de list1 et list2 sont séparés par un séparateur, comme le sont les éléments de la liste retournée.

  • list_join(with_separator, list1, separator1 [, list2, separator2]*) – retourne une liste faite en joignant les éléments des listes sources (list1 etc) en utilisant with_separator entre les éléments de la liste résultante. Les éléments de chaque liste[123...] source sont séparés par le séparateur[123...] associé. Une liste peut contenir zéro valeur. Il peut s’agir d’un champ comme publisher qui n’a qu’une seule valeur, c’est à dire une liste d’un seul élément. Les doublons sont supprimés en utilisant une comparaison insensible à la casse. Les éléments sont retournés dans l’ordre où ils apparaissent dans les listes sources. Si les éléments des listes ne diffèrent que par la casse des lettres, c’est la dernière qui est utilisée. Tous les séparateurs peuvent comporter plus d’un caractère.

    Exemple:

    program:
      list_join('#@#', $authors, '&', $tags, ',')
    

    Vous pouvez utiliser list_join sur les résultats des appels précédents à list_join comme suit

    program:
      a = list_join('#@#', $authors, '&', $tags, ',');
      b = list_join('#@#', a, '#@#', $#genre, ',', $#people, '&', 'some value', ',')
    

    Vous pouvez utiliser des expressions pour générer une liste. Par exemple, supposons que vous vouliez des éléments pour auteurs et #genre, mais avec le genre changé en mot « Genre : «  suivi de la première lettre du genre, c’est-à-dire que le genre « Fiction » devient « Genre : F ». Ce qui suit fera l’affaire

    program:
      list_join('#@#', $authors, '&', list_re($#genre, ',', '^(.).*$', 'Genre: \1'),  ',')
    
  • list_re(src_list, separator, include_re, opt_replace) – Construit une liste en séparant d’abord src_list en éléments en utilisant le caractère separator. Pour chaque élément de la liste, vérifiez s’il correspond à include_re. Si c’est le cas, ajoutez-le à la liste à retourner. Si opt_replace n’est pas une chaîne vide, il faut appliquer le remplacement avant d’ajouter l’élément à la liste retournée.

  • list_re_group(src_list, separator, include_re, search_re [, template_for_group]*) – Comme list_re sauf que les remplacements ne sont pas optionnels. Elle utilise re_group(item, search_re, template ...) pour effectuer les remplacements.

  • list_remove_duplicates(list, separator) – retourne une liste faite en supprimant les éléments en double dans list. Si les éléments ne diffèrent que par la casse, le dernier est retourné. Les éléments de list sont séparés par separator, comme le sont les éléments de la liste retournée.

  • list_sort(list, direction, separator) – retourne list triée en utilisant un tri lexical insensible à la casse. Si direction est zéro, list est triée de manière ascendante, sinon de manière descendante. Les éléments de la liste sont séparés par le separator, comme le sont les éléments de la liste retournée.

  • list_split(list_val, sep, id_prefix) – divise list_val en valeurs séparées en utilisant sep, puis affecte les valeurs à des variables locales nommées id_prefix_N où N est la position de la valeur dans la liste. Le premier élément a la position 0 (zéro). La fonction renvoie le dernier élément de la liste.

    Exemple:

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

    est équivalent à

    var_0 = 'one';
    var_1 = 'two';
    var_2 = 'foo
    
  • list_union(list1, list2, separator) – retourne une liste faite en fusionnant les éléments de list1 et list2, en supprimant les éléments en double en utilisant une comparaison insensible à la casse. Si les éléments diffèrent selon la casse, c’est celui de la « list1 » qui est utilisé. Les éléments de « list1 » et « list2 » sont séparés par un « separator », tout comme les éléments de la liste retournée. Alias : merge_lists(), list_union()

  • mod(x, y) – renvoie le floor du reste de x / y. Lance une exception si x ou y n’est pas un nombre.

  • multiply(x [, y]*) – renvoie le produit de ses arguments. Lance une exception si l’un des arguments n’est pas un nombre. Cette fonction peut généralement être remplacée par l’opérateur *.

  • not(valeur) – retourne la chaîne « 1 » si la valeur est vide, sinon retourne la chaîne vide. Cette fonction peut généralement être remplacée par l’opérateur unaire not (!).

  • ondevice() – retourne la chaîne Yes' si ondevice est défini, sinon retourne la chaîne vide.

  • or(value [, value]*) – retourne la chaîne '1' si une valeur n’est pas vide, sinon retourne la chaîne vide. Vous pouvez avoir autant de valeurs que vous le souhaitez. Cette fonction peut généralement être remplacée par l’opérateur ||. Une raison pour laquelle elle ne peut pas être remplacée est que le court-circuitage modifiera les résultats à cause d’effets secondaires.

  • print(a [, b]*) – imprime les arguments sur la sortie standard. A moins que vous ne lanciez calibre depuis la ligne de commande (calibre-debug -g), la sortie ira dans un trou noir. La fonction print retourne toujours son premier argument.

  • range(start, stop, step, limit) – renvoie une liste de nombres générés en bouclant sur la plage spécifiée par les paramètres start, stop, et step, avec une longueur maximale de limit. La première valeur produite est « start ». Les valeurs suivantes sont next_v = current_v + step. La boucle continue tant que next_v < stop si step` est positif, sinon tant que next_v > stop. Une liste vide est produite si start échoue le test : start >= stop si step est positif. Le paramètre limit définit la longueur maximale de la liste et a une valeur par défaut de 1000. Les paramètres start, step, et limit sont facultatifs. Appeler range() avec un argument spécifie stop. Deux arguments spécifient «  start «  et «  stop « . Trois arguments spécifient «  start « , «  stop «  et «  step « . Quatre arguments spécifient «  start « , «  stop « , «  step «  et «  limit « . Exemples

    range(5) -> '0, 1, 2, 3, 4'
    range(0, 5) -> '0, 1, 2, 3, 4'
    range(-1, 5) -> '-1, 0, 1, 2, 3, 4'
    range(1, 5) -> '1, 2, 3, 4'
    range(1, 5, 2) -> '1, 3'
    range(1, 5, 2, 5) -> '1, 3'
    range(1, 5, 2, 1) -> error(limit exceeded)
    
  • raw_field(lookup_name [, optional_default]) – renvoie le champ de métadonnées nommé par lookup_name sans appliquer de formatage. Il évalue et renvoie le second argument facultatif optional_default si la valeur du champ est indéfinie (None).

  • raw_list(lookup_name, separator) – renvoie la liste de métadonnées nommée par lookup_name sans appliquer de formatage ou de tri, avec les éléments séparés par le séparateur.

  • re_group(value, pattern [, template_for_group]*) – renvoie une chaîne faite en appliquant le motif de l’expression régulière à value et en remplaçant chaque instance trouvée par la valeur renvoyée par le modèle correspondant. En Mode Programme Modèle, comme pour les fonctions template et eval, vous utilisez [[` pour { et ]] pour }.

    L’exemple suivant recherche une série comportant plus d’un mot et met en majuscule le premier mot

    program: re_group(field('series'), "(\S* )(.*)", "{$:uppercase()}", "{$}")'}
    
  • round(x) – renvoie l’entier le plus proche de x. Envoie une exception si x n’est pas un nombre.

  • series_sort() – renvoie la valeur de tri des séries.

  • strcat(a [, b]*) – peut avoir n’importe quel nombre d’arguments. Renvoie une chaîne constituée par la concaténation de tous les arguments.

  • strcat_max(max, string1 [, prefix2, string2]*) – Renvoie une chaîne formée par la concaténation des arguments. La valeur retournée est initialisée à string1. Les chaînes formées à partir des paires prefix, string sont ajoutées à la fin de la valeur tant que la longueur de la chaîne résultante est inférieure à max. Les préfixes peuvent être vides. Retourne string1 même si string1 est plus long que max. Vous pouvez passer autant de paires prefix, string que vous le souhaitez.

  • strcmp(x, y, lt, eq, gt) – effectue une comparaison lexicale insensible à la casse de x et y. Elle retourne lt si x < y, eq si x == y, sinon gt. Cette fonction peut souvent être remplacée par l’un des opérateurs de comparaison lexicale (==, >, <, etc.).

  • strcmpcase(x, y, lt, eq, gt) – effectue une comparaison sensible à la casse de x et y en tant que chaînes de caractères. Retourne lt si x < y. Retourne eq si x == y. Sinon, retourne gt.

    Note : Ce n’est PAS le comportement par défaut utilisé par calibre, par exemple, dans les opérateurs de comparaison lexicale (==, >, <, etc.). Cette fonction pourrait provoquer des résultats inattendus, utilisez de préférence strcmp() lorsque cela est possible.

  • strlen( value) – Retourne la longueur de la chaîne value.

  • substr(str, start, end) – renvoie les caractères de début jusqu’à fin de str. Le premier caractère dans str est le caractère zéro. Si end est négatif, cela indique que beaucoup de caractères sont comptés à partir de la droite. Si end est zéro, cela indique le dernier caractère. Par exemple, substr('12345', 1, 0) renvoie '2345', et substr('12345', 1, -1) renvoie '234'.

  • substract(x, y) – renvoie x / y. Lance une exception si x ou y ne sont pas des nombres. Cette fonction peut généralement être remplacée par l’opérateur -.

  • switch_if([test_expression, value_expression,]+ else_expression) – pour chaque paire test_expression, value_expression, vérifie si test_expression est vraie (non vide) et si c’est le cas retourne le résultat de value_expression. Si aucune expression_test n’est vraie, alors le résultat de expression_sel est retourné. Vous pouvez avoir autant de paires expression_test, expression_valeur que vous le souhaitez.

  • today() – retourne une chaîne date+heure pour aujourd’hui (now). Cette valeur est conçue pour être utilisée dans format_date ou days_between, mais peut être manipulée comme toute autre chaîne. La date est au format `ISO `_ date/heure.

  • template(x) – évalue x comme un modèle. L’évaluation est faite dans son propre contexte, ce qui signifie que les variables ne sont pas partagées entre l’appelant et l’évaluation du modèle.

  • to_hex(val) – renvoie la chaîne val encodée en hexadécimal. Ceci est utile lors de la construction d’URLs calibre.

  • urls_from_identifiers(identifiers, sort_results) – donne une liste d’identifiants séparée par des virgules, où un identifiant est une paire de valeurs séparées par des deux points (id_name:id_value), renvoie une liste d’URL HTML séparées par des virgules, générées à partir des identifiants. La liste n’est pas triée si sort_results vaut 0 (caractère ou nombre), sinon elle est triée par ordre alphabétique du nom de l’identifiant. Les URL sont générées de la même manière que la colonne d’identifiants intégrée lorsqu’elle est affichée dans Détails du livre.

Programmes plus complexes dans les expressions modèles - Mode Programme de Modèles

Le Mode Programme de Modèle (MPM) est un mélange du Mode de Programme Général et du Mode Fonction Unique. Le MPM diffère du Mode Fonction Unique en ce qu’il permet d’écrire des expressions de modèle qui font référence à d’autres champs de métadonnées, utilisent des fonctions imbriquées, modifient des variables et font de l’arithmétique. Il diffère du Mode Programme Général en ce que le modèle est contenu entre les caractères {` et } et ne commence pas par le mot program:. La partie programme du modèle est une liste d’expressions du Mode Programme Général.

Exemple : supposons que vous vouliez qu’un modèle affiche la série d’un livre s’il en a une, sinon la valeur d’un champ personnalisé #genre. Vous ne pouvez pas faire cela dans le mode Mode Fonction Unique car vous ne pouvez pas faire référence à un autre champ de métadonnées dans une expression de modèle. En MPM, vous le pouvez, comme le montre l’expression suivante

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

L’exemple montre plusieurs choses :

  • MPP est utilisé si l’expression commence par :' et se termine par '}. Tout le reste est supposé être en Mode Fonction Unique.

  • la variable $ représente le champ nommé dans le modèle : l’expression sur laquelle on opère, #series dans ce cas.

  • les fonctions doivent être données avec tous leurs arguments. Il n’y a pas de valeur par défaut. Par exemple, les fonctions intégrées standard doivent recevoir un paramètre initial supplémentaire indiquant le champ source.

  • les espaces sont ignorés et peuvent être utlisés n’importe où dans l’expression.

  • les chaînes constantes sont entre guillemets, soit ' ou ".

Toutes les fonctions listées dans les rubriques Mode Fonction Unique et Mode Programme Général peuvent être utilisées dans le MPM.

En MPM, l’utilisation des caractères {` et } dans les chaînes de caractères peut conduire à des erreurs ou des résultats inattendus parce qu’ils confondent le processeur de modèle. Il essaie de les traiter comme des limites d’expression de modèle et non comme des caractères. Dans certains cas, mais pas dans tous, vous pouvez remplacer un { par [[ et un } par ]]. En général, si votre programme contient des caractères { et }, vous devriez utiliser le Mode Programme Général.

Comme pour le Mode Général de Programme, pour les fonctions documentées sous Mode Fonction Unique, vous devez fournir la valeur sur laquelle la fonction doit agir comme premier paramètre en plus des paramètres documentés. En MPM, vous pouvez utiliser $ pour accéder à la valeur spécifiée par le lookup name de l’expression modèle.

Mode Programmation Python

Mode Programmation Python (MPP) vous permet d’écrire des modèles en utilisant le langage python natif et l’API de calibre. L’API de la base de données sera la plus utile ; une discussion plus approfondie dépasse le cadre de ce manuel. Les modèles MPP sont plus rapides et peuvent faire des opérations plus compliquées, mais vous devez savoir comment écrire du code en python en utilisant l’API calibre.

Un modèle de MPP commence par :

python:
def evaluate(book, context):
    # book is a calibre metadata object
    # context is an instance of calibre.utils.formatter.PythonTemplateContext,
    # which currently contains the following attributes:
    # db: a calibre legacy database object.
    # globals: the template global variable dictionary.
    # arguments: is a list of arguments if the template is called by a GPM template, otherwise None.
    # funcs: used to call Built-in/User functions and Stored GPM/Python templates.
    # Example: context.funcs.list_re_group()

    # your Python code goes here
    return 'a string'

Vous pouvez ajouter le texte ci-dessus à votre modèle en utilisant le menu contextuel, généralement accessible par un clic droit. Les commentaires ne sont pas significatifs et peuvent être supprimés. Vous devez utiliser l’indentation python.

L’objet context prend en charge str(context) qui renvoie une chaîne de caractères du contenu du contexte, et context.attributes qui renvoie une liste des noms d’attributs dans le contexte.

L’attribut context.funcs permet d’appeler les fonctions modèles intégrés et utilisateurs, ainsi que les modèles stockés MPG/Python, afin que vous puissiez les exécuter directement dans votre code. Les fonctions sont récupérées à l’aide de leur nom. Si le nom entre en conflit avec un mot clé Python, ajoutez un trait de underscore à la fin du nom. Exemples :

context.funcs.list_re_group()
context.funcs.assert_()

Voici un exemple de modèle MPP qui produit une liste de tous les auteurs d’une série. La liste est stockée dans une Colonne construite à partir d’autres colonnes, se comporte comme des étiquettes. Elle est affichée dans Détails du livre et l’option sur des lignes séparées est cochée (dans Préférences → Apparence et présentation → Détails du livre). Cette option exige que la liste soit séparée par des virgules. Pour satisfaire à cette exigence, le modèle convertit les virgules dans les noms d’auteurs en points-virgules puis construit une liste d’auteurs séparés par des virgules. Les auteurs sont ensuite triés, c’est pourquoi le modèle utilise author_sort.

python:
def evaluate(book, context):
    if book.series is None:
        return ''
    db = context.db.new_api
    ans = set()
    # Get the list of books in the series
    ids = db.search(f'series:"={book.series}"', '')
    if ids:
        # Get all the author_sort values for the books in the series
        author_sorts = (v for v in db.all_field_for('author_sort', ids).values())
        # Add the names to the result set, removing duplicates
        for aus in author_sorts:
            ans.update(v.strip() for v in aus.split('&'))
    # Make a sorted comma-separated string from the result set
    return ', '.join(v.replace(',', ';') for v in sorted(ans))

La sortie dans Détails du livre ressemble à ceci :

Dialogue de conversion des livres numériques

Modèles stockés

Les modes Mode Général de Programmation et Mode Programmation Python permettent d’enregistrer des modèles et d’appeler ces modèles à partir d’un autre modèle, de la même manière que l’on appelle des fonctions stockées. Vous enregistrez les modèles en utilisant Préférences → Avancées → Modèles de fonctions. Plus d’informations sont fournies dans cette boîte de dialogue. Vous appelez un modèle de la même manière que vous appelez une fonction, en passant des arguments positionnels si vous le souhaitez. Un argument peut être n’importe quelle expression. Exemples d’appel d’un modèle, en supposant que le modèle stocké est nommé foo

  • foo() – appelle le modèle en ne passant aucun argument.

  • foo(a, b) appelle le modèle en passant les valeurs des deux variables a et b.

  • foo(if field('series') then field('series_index') else 0 fi) – si le livre a series alors passez le series_index, sinon passez la valeur 0.

En MGP, vous récupérez les arguments passés dans l’appel au modèle stocké en utilisant la fonction arguments. Cette fonction déclare et initialise des variables locales, en fait des paramètres. Les variables sont positionnelles ; elles obtiennent la valeur du paramètre donné dans l’appel à la même position. Si le paramètre correspondant n’est pas fourni dans l’appel, alors arguments attribue à cette variable la valeur par défaut fournie. S’il n’y a pas de valeur par défaut, la variable prend la valeur de la chaîne vide. Par exemple, la fonction arguments suivante déclare 2 variables, key, alternate :

arguments(key, alternate='series')

Par exemple, en supposant encore une fois que le modèle stocké est nommé foo :

  • foo('#myseries') – l’argument key se voit attribuer la valeur myseries' et l’argument alternate se voit attribuer la valeur par défaut 'series'.

  • foo('series', '#genre') la variable key prend la valeur 'series' et la variable alternate prend la valeur '#genre'.

  • foo() – la variable key se voit attribuer la chaîne vide et la variable alternate se voit attribuer la valeur 'series'.

En MPP, les arguments sont passés dans le paramètre arguments, qui est une liste de chaînes de caractères. Il n’y a aucun moyen de spécifier des valeurs par défaut. Vous devez vérifier la longueur de la liste arguments pour être sûr que le nombre d’arguments est celui que vous attendez.

Une façon simple de tester les modèles stockés est d’utiliser le dialogue « Testeur de modèle ». Pour faciliter l’accès, donnez-lui un raccourci clavier dans Préférences → Avancé → Raccourcis clavier → Tester le modèle`. Donner un raccourci au dialogue Modèles stockés aidera à passer plus rapidement du testeur à l’édition du code source du modèle stocké.

Fournir des informations supplémentaires aux modèles

Un développeur peut choisir de transmettre des informations supplémentaires au processeur du modèle, telles que des métadonnées de livre spécifiques à l’application ou des informations sur ce qui est demandé au processeur. Un modèle peut accéder à ces informations et les utiliser pendant l’évaluation.

Développeur : comment transmettre des informations supplémentaires

L’information supplémentaire est un dictionnaire Python contenant des paires nom_variable : valeur_variable où les valeurs doivent être des chaînes. Le modèle peut accéder au dictionnaire, en créant des variables locales nommées nom_de_variable contenant la valeur variable_valeur. L’utilisateur ne peut pas changer le nom, il est donc préférable d’utiliser des noms qui n’entreront pas en collision avec d’autres variables locales du modèle, par exemple en préfixant le nom par un trait de soulignement.

Ce dictionnaire est passé au processeur de modèle (le formatter) en utilisant le paramètre nommé global_vars=votre_dict. La signature complète de la méthode est :

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

Rédacteur de modèles : comment accéder aux informations complémentaires

Vous accédez aux informations supplémentaires (le dictionnaire globals) dans un modèle en utilisant la fonction de modèle :

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

id est un nom de variable légale quelconque. Cette fonction vérifie si les informations supplémentaires fournies par le développeur contiennent le nom. Si c’est le cas, la fonction attribue la valeur fournie à une variable locale modèle avec ce nom. Si le nom ne figure pas dans les informations supplémentaires et si une « expression » est fournie, cette « expression » est évaluée et le résultat est attribué à la variable locale. Si ni une valeur ni une expression n’est fournie, la fonction attribue la chaîne vide ('') à la variable locale.

Un modèle peut définir une valeur dans le dictionnaire globals en utilisant la fonction de modèle:

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

Cette fonction définit la paire clé:valeur du dictionnaire globals id:valuevalue est la valeur de la variable locale du modèle id. Si cette variable locale n’existe pas, alors valeur est fixée au résultat de l’évaluation de expression.

Notes sur la différence entre les modes

Les trois modes de programmation, Mode Fonction Simple (MFS), Mode Modèle de Programmation (MMP), et Mode Général de Programmation (MGP), fonctionnent différemment. Le MFS est destiné à être “simple” et cache donc beaucoup de bits de langage de programmation.

Différences :

  • Dans MFS, la valeur de la colonne est toujours passée comme premier argument “invisible” à une fonction incluse dans le modèle.

  • Le MFS ne supporte pas la différence entre les variables et les chaînes de caractères ; toutes les valeurs sont des chaînes de caractères.

  • Le modèle SFM suivant renvoie soit le nom de la série, soit la chaîne « pas de série »

    {series:ifempty(no series)}
    

    Le modèle équivalent dans MPM est

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

    Le modèle équivalent dans MGP est

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

    Le premier argument de ifempty est la valeur du champ série. Le second argument est la chaîne no series. Dans SFM, le premier argument, la valeur du champ, est automatiquement passé (l’argument invisible).

  • Plusieurs fonctions du modèle, par exemple booksize() et current_library_name(), ne prennent aucun argument. En raison de l“« argument invisible », vous ne pouvez pas utiliser ces fonctions dans SFM.

  • Les fonctions imbriquées, où une fonction appelle une autre fonction pour calculer un argument, ne peuvent pas être utilisées dans SFM. Par exemple, ce modèle, destiné à renvoyer les 5 premiers caractères de la valeur de la série en majuscules, ne fonctionnera pas dans SFM

    {series:uppercase(substr(0,5))}
    
  • MPM et MPG soutiennent des fonctions imbriquées. Le modèle ci-dessus dans MPM serait

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

    Dans MPG, ce serait

    program: uppercase(substr(field('series'), 0,5))
    
  • Comme indiqué dans la section Mode de Programmation des Modèles ci-dessus, l’utilisation des caractères { et } dans les chaînes de caractères MPM peut conduire à des erreurs ou à des résultats inattendus car ils perturbent le processeur de modèles. Il essaie de les traiter comme des limites de modèles et non comme des caractères. Dans certains cas, mais pas dans tous, vous pouvez remplacer un { par [[ et un } par ]]`. En général, si votre programme contient des caractères ``{ et }, vous devriez utiliser le Mode Général de Programmation.

Fonctions des modèles Python définis par l’utilisateur

Vous pouvez ajouter vos propres fonctions Python au processeur de modèles. Ces fonctions peuvent être utilisées dans l’un des trois modes de programmation du modèle. Les fonctions sont ajoutées en allant dans Préférences  →  Avancé  →  Fonctions de modèle. Les instructions sont affichées dans cette boite de dialogue.

Notes spéciales pour la sauvergarde/l’envoi des modèles

Un traitement spécial est appliqué quand un modèle est utilisé dans un modèle Enregistrer sur le disque ou Envoyer au périphérique. Les valeurs des champs sont nettoyées, les caractères qui sont propres aux systèmes de fichiers sont remplacées par des traits de soulignement, y compris les barres obliques. Cela signifie que le texte d’un champ ne peut pas être utilisé pour créer des dossiers. Toutefois, les barres obliques ne sont pas modifiés dans des chaînes préfixe ou suffixe. Vous pouvez donc insérer des barres obliques qui et provoquer ainsi la création de dossiers. Ainsi, vous pouvez créer une structure de dossier avec des profondeurs variables.

Par exemple, supposons que nous voulons que la structure des dossiers soit series/series_index - titre, en prévoyant que si la série n’existe pas, alors le titre devrait être dans le dossier racine (le premier dossier, pas le sous-dossier). Le modèle pour faire cela est :

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

La barre oblique et le trait d’union apparaissent uniquement si la série n’est pas vide.

La fonction de recherche nous permet de faire le traitement encore plus poussé. Par exemple, supposons que si un livre est dans une série, alors nous voulons que la structure soit la suivante : series/series index - title.fmt.. Si le livre n’est pas dans une série, alors nous voulons que la structure des dossiers soit genre/author_sort/title.fmt. Si le livre n’a pas de genre, alors nous voulons utiliser “Inconnu”. Nous voulons deux chemins de répertoire totalement différents en fonction de la valeur de la série.

Pour accomplir cela, nous :

  1. Créer un champ composite (donner-lui le nom de recherche #aa) contenant {series}/{series_index} - {titre}. Si la série n’est pas vide, alors ce modèle produira series/series_index - titre.

  2. Créons une champ composite (appelons-le #bb) contenant {#genre:ifempty(Unknown)}/{author_sort}/{title}. Ce modèle produit genre/author_sort/title, où un genre vide est remplacé par Inconnu.

  3. Paramétrez le modèle de sauvegarde à {series:lookup(.,#aa,#bb)}. Ce modèle choisit le champ composite #aa si série n’est pas vide, et le champ composite #bb si série est vide. Nous avons dès lors deux chemins de sauvegarde complètement différents, dépendant du fait que series soit vide ou pas.

Astuces

  • Utilisez le Testeur de Modèles pour tester les modèles. Ajoutez le testeur au menu contextuel des livres de la bibliothèque et/ou donnez-lui un raccourci clavier.

  • Les modèles peuvent utiliser d’autres modèles en faisant référence à des colonnes composites construites avec le modèle souhaité. Vous pouvez également utiliser des Modèles Stockés comme alternative.

  • Dans un tableau de connexions, vous pouvez paramétrer un champ à vide (ou quelque soit sont équivalent à vide) en utilisant le modèle spécial {}. Ce modèle sera toujours évalué à une chaîne vide.

  • La technique indiquée ci-dessus pour montrer les nombre même s’ils ont une valeur zéro fonctionne avec le champ standard series_index.

Référence de la fonction