calibre 템플릿 언어¶
calibre 템플릿 언어는 파일 경로 지정, 값 서식 지정, 사용자가 지정한 열의 값 계산 같은 작업에 calibre 전반에서 사용되는 calibre 전용 언어이다. 예:
calibre 라이브러리의 파일을 디스크나 전자책 리더에 저장할 때 폴더 구조와 파일 이름을 지정한다.
calibre 책 목록에 아이콘과 색상을 추가하는 규칙을 정의한다.
다른 열의 데이터를 담는 `가상 열`을 정의한다.
고급 라이브러리 검색.
고급 메타데이터 검색 및 바꾸기.
이 언어는 `템플릿`이라는 개념을 중심으로 구성되어 있으며, 어떤 책 메타데이터를 사용할지, 그 메타데이터에 대해 어떤 계산을 수행할지, 그리고 어떻게 서식화할지를 지정한다.
기본 템플릿¶
기본 템플릿은 하나 이상의 template expression``으로 구성된다. ``template expression``은 텍스트와 중괄호(``{}) 안의 이름으로 이루어지며, 처리 중인 책의 해당 메타데이터로 치환된다. 예를 들어 calibre에서 기기로 책을 저장할 때 사용하는 기본 템플릿에는 4개의 ``template expression``이 있다:
{author_sort}/{title}/{title} - {authors}
“The Foundation”의 저자가 “Isaac Asimov”인 책에 대해 이 템플릿은 다음과 같이 된다:
Asimov, Isaac/The Foundation/The Foundation - Isaac Asimov
슬래시는 {} 사이에 있지 않으므로 ``template expression``이 아니다. 이런 텍스트는 있는 위치에 그대로 남는다. 예를 들어 템플릿이 다음과 같다면:
{author_sort} Some Important Text {title}/{title} - {authors}
그러면 “The Foundation”에 대해 템플릿은 다음을 만든다:
Asimov, Isaac Some Important Text The Foundation/The Foundation - Isaac Asimov
``template expression``은 열의 ``lookup name``을 사용하여 calibre에서 사용할 수 있는 모든 메타데이터(사용자가 직접 만든 사용자 정의 열 포함)에 접근할 수 있다. `column`(때로는 `fields`라고도 부름)의 lookup name을 찾으려면 calibre 책 목록의 열 머리글 위에 마우스를 올리면 된다. 사용자 정의 열의 lookup name은 항상 ``#``으로 시작한다. 시리즈 형식 열에는 추가로 ``#lookup name_index``라는 필드가 있으며, 이 값은 해당 책의 시리즈 내 번호이다. 예를 들면:
표준 열 기반 필드 외에 다음도 사용할 수 있다:
{formats}- 책에 대해 calibre 라이브러리에서 사용 가능한 형식 목록
{identifiers:select(isbn)}- 책의 ISBN
주어진 책에 대해 해당 필드의 메타데이터가 정의되어 있지 않으면 템플릿의 그 필드는 빈 문자열('')로 치환된다. 예를 들어 다음 템플릿을 보자:
{author_sort}/{series}/{title} {series_index}
아시모프의 책 “Second Foundation”이 “Foundation” 시리즈에 속해 있다면 템플릿은 다음을 만든다:
Asimov, Isaac/Foundation/Second Foundation 3
책에 시리즈가 입력되어 있지 않으면 템플릿은 다음을 만든다:
Asimov, Isaac/Second Foundation
템플릿 처리기는 여러 개의 슬래시와 앞뒤 공백을 자동으로 제거한다.
고급 서식 지정¶
메타데이터 치환 외에도 템플릿은 추가 텍스트를 조건부로 포함하고, 치환된 데이터의 서식을 제어할 수 있다.
조건부 텍스트 포함
필드가 비어 있지 않을 때만 출력에 텍스트를 표시하고 싶을 때가 있다. 흔한 예는 series``와 ``series_index``로, 아무것도 출력하지 않거나 하이픈으로 구분된 두 값을 출력하고 싶을 수 있다. calibre는 이 경우를 특별한 ``template expression 문법으로 처리한다.
예를 들어 위의 Foundation 예제를 사용해 템플릿이 `Foundation - 3 - Second Foundation`을 만들기를 원한다고 하자. 다음 템플릿은 그 출력을 만든다:
{series} - {series_index} - {title}
하지만 책에 시리즈가 없으면 템플릿은 `- - the title`을 만들며, 이는 보통 원하는 결과가 아니다. 일반적으로는 불필요한 하이픈 없이 제목만 나오기를 원한다. 다음 템플릿 문법을 사용하면 그렇게 할 수 있다:
{field:|prefix_text|suffix_text}
이 ``template expression``은 ``field``의 값이 `XXXX`이면 결과가 `prefix_textXXXXXsuffix_text`가 된다는 뜻이다. ``field``가 비어 있으면(값이 없으면) 접두사와 접미사는 무시되므로 결과는 빈 문자열(아무것도 없음)이다. 접두사와 접미사에는 공백이 들어갈 수 있다.
접두사나 접미사에 서브템플릿(`{ … }`)이나 함수(아래 참조)를 사용하지 마라.
이 문법을 사용하면 위의 시리즈 없음 문제를 다음 템플릿으로 해결할 수 있다:
{series}{series_index:| - | - }{title}
하이픈은 책에 시리즈 번호가 있을 때만 포함되며, 시리즈 번호는 시리즈가 있을 때만 존재한다. Foundation 예제를 계속 사용하면 템플릿은 `Foundation - 1 - Second Foundation`을 만든다.
참고:
접두사나 접미사를 사용할 경우
lookup name뒤에 콜론을 반드시 넣어야 한다.|문자는 둘 다 쓰거나 아예 쓰지 말아야 한다. ``{field:| - }``처럼 하나만 쓰는 것은 허용되지 않는다.``{series:|| - }``처럼 접두사나 접미사 중 하나에 텍스트를 넣지 않아도 된다. 템플릿 ``{title:||}``는 ``{title}``와 같다.
서식 지정
``series_index``를 앞을 0으로 채운 세 자리 숫자로 표시하고 싶다고 하자. 다음과 같이 하면 된다:
{series_index:0>3s}- 앞을 0으로 채운 세 자리
뒤를 0으로 채우려면 다음을 사용한다:
{series_index:0<3s}- 뒤를 0으로 채운 세 자리
시리즈 번호에 1.1 같은 소수 값이 포함되어 있다면 소수점 위치를 맞추고 싶을 수 있다. 예를 들어 1과 2.5를 01.00과 02.50으로 표시해, 사전식 정렬을 사용하는 기기에서도 올바르게 정렬되게 하고 싶을 수 있다. 이 경우 다음을 사용한다:
{series_index:0>5.2f}- 앞을 0으로 채운 두 자리 숫자, 소수점, 그리고 소수점 이하 두 자리로 구성된 총 5자
데이터의 처음 두 글자만 원한다면 다음을 사용한다:
{author_sort:.2}- 저자 정렬 이름의 처음 두 글자만
calibre 템플릿 언어의 서식 지정 상당수는 Python에서 왔다. 이러한 고급 서식 지정 연산의 문법에 대한 자세한 내용은 `Python 문서 <https://docs.python.org/3/library/string.html#formatstrings>`_를 참조하라.
템플릿을 사용해 사용자 정의 열 정의하기¶
템플릿은 calibre 메타데이터에 없는 정보를 표시하거나, 메타데이터를 calibre의 기본 형식과 다르게 표시하는 데 사용할 수 있다. 예를 들어 calibre가 표시하지 않는 ISBN 필드를 보여주고 싶을 수 있다. 이를 위해 다른 열로부터 만들어진 열 형식(이하 합성 열)의 사용자 정의 열을 만들고, 표시할 텍스트를 생성하는 템플릿을 제공하면 된다. 이 열에는 템플릿 평가 결과가 표시된다. 예를 들면:
복합 열은 템플릿을 포함한 모든 템플릿 옵션을 사용할 수 있습니다.
참고: 합성 열에 표시되는 데이터는 직접 편집할 수 없다. 대신 원본 열을 편집해야 한다. 합성 열을 더블클릭하는 등으로 편집하려 하면 calibre는 실제 데이터가 아니라 템플릿 편집기를 연다.
템플릿과 플러그보드¶
플러그보드는 기기로 보내기와 디스크에 저장 작업 중 책에 기록되는 메타데이터를 변경하는 데 사용한다. 플러그보드를 사용하면 책 메타데이터에 쓸 데이터를 제공하는 템플릿을 지정할 수 있다. 수정 가능한 필드는 authors, author_sort, language, publisher, tags, title, title_sort이다. 이 기능은 정렬이나 표시 문제를 해결하기 위해 기기의 책에 다른 메타데이터를 쓰고 싶은 사용자에게 유용하다.
플러그보드를 만들 때는 해당 플러그보드가 사용될 형식과 장치를 지정한다. 형식을 저장할 때(기기로 보내는 것이 아니라) 사용하는 특수 장치로 ``save_to_disk``가 제공된다. 형식과 장치를 선택한 후에는 변경할 메타데이터 필드를 선택하고, 새 값을 제공할 템플릿을 지정한다. 이 템플릿들은 대상 필드에 `연결`되므로 `plugboards`라는 이름이 붙었다. 물론 이러한 템플릿에서 합성 열을 사용할 수도 있다.
플러그보드는 매우 유연하며 Single Function Mode, Template Program Mode, General Program Mode, Python Template mode로 작성할 수 있다.
플러그보드가 적용될 수 있을 때(콘텐츠 서버, 디스크에 저장, 기기로 보내기) calibre는 정의된 플러그보드를 검색하여 해당 형식과 장치에 맞는 올바른 플러그보드를 선택한다. 예를 들어 EPUB 책을 ANDROID 장치로 보낼 때 적절한 플러그보드를 찾기 위해 calibre는 다음 순서로 플러그보드를 검색한다:
형식과 장치가 정확히 일치하는 플러그보드. 예:
EPUB및ANDROID형식은 정확히 일치하고 장치는 특수 선택인
any device``인 플러그보드. 예: ``EPUB및any device특수 선택인
any format``과 장치의 정확한 일치가 있는 플러그보드. 예: ``any format및ANDROIDany format및 ``any device``가 지정된 플러그보드
tags 필드와 authors 필드는 둘 다 여러 항목을 담을 수 있기 때문에 특별하게 처리된다. 한 책에는 여러 태그와 여러 저자가 있을 수 있다. 이 두 필드 중 하나를 변경하도록 지정하면 템플릿 결과를 검사하여 항목이 둘 이상인지 확인한다. 태그의 경우 calibre는 쉼표가 있는 곳에서 결과를 분리한다. 예를 들어 템플릿이 Thriller, Horror``를 만들면 결과는 ``Thriller``와 ``Horror 두 개의 태그가 된다. 태그에 쉼표를 넣는 방법은 없다.
저자도 같은 방식으로 처리되지만, 구분 문자로 쉼표 대신 &`(앰퍼샌드)를 사용한다. 예를 들어 템플릿이 ``Blogs, Joe&Posts, Susan``을 만들면 책에는 ``Blogs, Joe``와 ``Posts, Susan` 두 명의 저자가 들어간다. 템플릿이 ``Blogs, Joe;Posts, Susan``을 만들면 책에는 다소 이상한 이름을 가진 한 명의 저자만 들어간다.
플러그보드는 디스크에 저장하거나 장치에 쓸 때 책에 기록되는 메타데이터에 영향을 준다. 하지만 ``디스크에 저장``과 ``기기로 보내기``가 파일 이름을 만들 때 사용하는 메타데이터에는 영향을 주지 않는다. 파일 이름은 대신 해당 환경설정 창에 입력된 템플릿을 사용해 구성된다.
템플릿에서 함수 사용하기 - Single Function Mode¶
일반적으로 제목 형식인 필드 값을 대문자로 표시하고 싶다고 하자. 이 경우 template functions`를 사용할 수 있다. 예를 들어 제목을 대문자로 표시하려면 ``{title:uppercase()}``처럼 ``uppercase` 함수를 사용한다. 제목 형식으로 표시하려면 ``{title:titlecase()}``를 사용한다.
함수는 템플릿의 형식 부분, 즉 : 뒤이자 첫 번째 | 앞(접두사/접미사가 없으면 닫는 } 앞)에 들어간다. 형식과 함수 참조를 둘 다 사용할 경우 함수는 두 번째 : 뒤에 온다. 함수는 템플릿에서 지정한 열의 값을 적절히 수정하여 반환한다.
함수 사용 문법은 다음 중 하나이다:
{lookup_name:function(arguments)}
{lookup_name:format:function(arguments)}
{lookup_name:function(arguments)|prefix|suffix}
{lookup_name:format:function(arguments)|prefix|suffix}
함수 이름 뒤에는 항상 여는 괄호와 닫는 괄호가 와야 한다. 일부 함수는 추가 값(인수)을 요구하며, 이 값들은 괄호 안에 넣는다. 인수는 쉼표로 구분한다. 문자 그대로의 쉼표(인수 구분자가 아닌 쉼표)는 백슬래시(\)를 앞에 붙여야 한다. 마지막 인수(또는 유일한 인수)에는 문자 그대로의 닫는 괄호를 넣을 수 없다.
함수는 형식 지정과 접두사/접미사보다 먼저 평가된다. 형식과 함수를 함께 사용하는 예는 아래를 참조하라.
중요: 프로그래밍 경험이 있다면 `Single Function Mode`의 문법이 예상과 다르다는 점에 주의하라. 문자열은 따옴표로 감싸지지 않으며 공백이 중요하다. 모든 인수는 상수로 간주되며 식은 없다.
함수 인수로 서브템플릿(`{ … }`)을 사용하지 마라. 대신 :ref:`Template Program Mode <template_mode>`와 :ref:`General Program Mode <general_mode>`를 사용하라.
Single Function Mode에서 함수 호출 시 참고 사항:
Single Function Mode에서 함수를 사용할 때 첫 번째 매개변수
value``는 템플릿에 지정된 필드의 내용으로 자동 대체된다. 예를 들어 템플릿 ``{title:capitalize()}``를 처리할 때 ``title필드의 내용이 capitalize 함수의value매개변수로 전달된다.함수 문서에서
[something]*표기는something``이 0회 이상 반복될 수 있음을 의미한다. ``[something]+표기는 ``something``이 1회 이상 반복됨을 의미한다(최소 한 번은 있어야 함).일부 함수는 정규식을 사용한다. 템플릿 언어에서 정규식 일치는 대소문자를 구분하지 않는다.
함수는 template_functions_reference`에 문서화되어 있다. 문서는 함수에 필요한 인수와 함수가 수행하는 일을 알려 준다. 예를 들어 다음은 :ref:`ff_ifempty 함수의 문서이다.
ifempty(value, text_if_empty)–value가 비어 있지 않으면 그 값을 반환하고, 비어 있으면text_if_empty를 반환합니다.
이 함수는 value``와 ``text_if_empty 두 인수를 요구한다. 하지만 지금은 Single Function Mode를 사용하고 있으므로 value 인수는 생략하고 ``text_if_empty``만 전달한다. 예를 들어 이 템플릿은:
{tags:ifempty(No tags on this book)}
책에 태그가 있으면 태그를 표시한다. 태그가 없으면 `이 책에는 태그가 없습니다`를 표시한다.
다음 함수들은 첫 번째 매개변수가 ``value``이므로 Single Function Mode에서 사용할 수 있다.
capitalize
(value)–value의 첫 글자는 대문자로, 나머지는 소문자로 바꿔 반환합니다.ceiling
(value)–value이상인 가장 작은 정수를 반환합니다.cmp
(value, y, lt, eq, gt)–value와y를 둘 다 숫자로 변환한 뒤 비교합니다.contains
(value, pattern, text_if_match, text_if_not_match)– 값이 정규식pattern과 일치하는지 검사합니다.date_arithmetic
(value, calc_spec, fmt)–calc_spec을 사용해value로부터 새 날짜를 계산합니다.encode_for_url
(value, use_plus)–use_plus설정에 따라 URL 에 사용할 수 있게value를 인코딩해 반환합니다. 값은 먼저 URL 인코딩되며, 이어서use_plus가0이면 공백을'+'로, 아니면%20으로 바꿉니다.floor
(value)–value이하인 가장 큰 정수를 반환합니다.format_date
(value, format_string)– 날짜 문자열이어야 하는value를format_string으로 형식화해 문자열로 반환합니다.format_duration
(value, template, [largest_unit])– 초 단위 숫자인value를 주, 일, 시, 분, 초를 보여 주는 문자열로 형식화합니다. 값이 실수이면 가장 가까운 정수로 반올림합니다.format_number
(value, template)–value를 숫자로 해석하고{0:5.2f},{0:,d},${0:5,.2f}같은 Python 서식 템플릿을 사용해 형식화합니다.fractional_part
(value)– 값의 소수점 이하 부분을 반환합니다.human_readable
(value)–value를 숫자로 간주하고 KB, MB, GB 등의 형식으로 표현한 문자열을 반환합니다.ifempty
(value, text_if_empty)–value가 비어 있지 않으면 그 값을 반환하고, 비어 있으면text_if_empty를 반환합니다.language_strings
(value, localize)–value로 전달된 언어 코드의 언어 이름을 반환합니다(이름과 코드는 여기 참조).list_contains
(value, separator, [ pattern, found_val, ]* not_found_val)–value를separator로 구분된 항목 목록으로 해석하고 각 항목을 정규식pattern과 비교합니다.list_count
(value, separator)– 값을separator로 구분된 항목 목록으로 해석하고 그 개수를 반환합니다.list_count_matching
(value, pattern, separator)–value를separator로 구분된 항목 목록으로 해석하고 정규식pattern과 일치하는 항목 수를 반환합니다.list_item
(value, index, separator)–value를separator로 구분된 항목 목록으로 해석하여index번째 항목을 반환합니다.list_sort
(value, direction, separator)– 대소문자를 구분하지 않는 사전식 정렬로value를 정렬해 반환합니다.lookup
(value, [ pattern, key, ]* else_key)– 패턴들을 순서대로value와 대조합니다.mod
(value, y)–value / y의 나머지에 대해floor를 적용한 값을 반환합니다.rating_to_stars
(value, use_half_stars)–value를 별(★) 문자 문자열로 반환합니다.re
(value, pattern, replacement)– 정규식을 적용한 뒤의value를 반환합니다.re_group
(value, pattern [, template_for_group]*)– 정규식pattern을value에 적용해 만들어진 문자열을 반환하고round
(value)–value에 가장 가까운 정수를 반환합니다.select
(value, key)–value를 각 항목이id:id_value형식인 콤마 구분 목록( calibreidentifier형식 )으로 해석합니다.shorten
(value, left_chars, middle_text, right_chars)–value의 축약형을 반환합니다.str_in_list
(value, separator, [ string, found_val, ]+ not_found_val)–value를separator로 구분된 항목 목록으로 해석한 뒤subitems
(value, start_index, end_index)– 장르처럼 계층 구조를 가진 태그형 항목 목록을 분해하는 함수입니다.sublist
(value, start_index, end_index, separator)–value를separator로 구분된 항목 목록으로 해석하고,start_index부터end_index까지의 항목으로 이루어진 새 목록을 반환합니다.substr
(value, start, end)–value의start번째 문자부터end번째 문자까지를 반환합니다.swap_around_articles
(value, separator)–value의 관사를 끝으로 옮겨 세미콜론으로 구분해 반환합니다.swap_around_comma
(value)–B, A형식의value를 받아A B를 반환합니다.switch
(value, [patternN, valueN,]+ else_value)– 각patternN, valueN쌍에 대해value가 정규식patternN과 일치하는지 검사하고test
(value, text_if_not_empty, text_if_empty)– 값이 비어 있지 않으면text_if_not_empty를, 비어 있으면text_if_empty를 반환합니다.transliterate
(value)–value의 단어 소리를 근사해 라틴 문자 알파벳 문자열로 반환합니다.
같은 템플릿에서 함수와 서식 함께 사용하기
정수 사용자 정의 열 #myint``를 ``003``처럼 앞을 0으로 채워 표시하고 싶다고 하자. 한 가지 방법은 ``0>3s 형식을 사용하는 것이다. 하지만 기본적으로 숫자(정수 또는 부동소수점)가 0이면 값은 빈 문자열로 표시되므로, 0 값은 000``이 아니라 빈 문자열이 된다. ``000``을 보고 싶다면 형식 문자열과 ``ifempty 함수를 함께 사용해 빈 값을 다시 0으로 바꾸면 된다. 템플릿은 다음과 같다:
{#myint:0>3s:ifempty(0)}
접두사와 접미사도 함께 사용할 수 있다. 숫자를 [003] 또는 ``[000]``처럼 보이게 하려면 다음 템플릿을 사용한다:
{#myint:0>3s:ifempty(0)|[|]}
General Program Mode¶
General Program Mode`(`GPM)는 `template expressions`를 `template language`로 작성한 프로그램으로 대체한다. 이 언어의 문법은 다음과 같이 정의된다:
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' | 'inlist_field' |
'==#' | '!=#' | '>=#' | '>#' | '<=#' | '<#'
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 | return_stmt
'(' 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 ] ] ')'
with_expr ::= 'with' top_expression ':' expression_list 'htiw'
list_expr ::= top_expression
break_expr ::= 'break'
continue_expr ::= 'continue'
return_stmt ::= 'return' top_expression
separator_expr ::= top_expression
start_expr ::= top_expression
stop_expr ::= top_expression
step_expr ::= top_expression
limit_expr ::= top_expression
참고:
``top_expression``은 항상 값을 가진다. ``expression_list``의 값은 목록에서 마지막 ``top_expression``의 값이다. 예를 들어 식 목록 ``1;2;’foobar’;3``의 값은 ``3``이다.
논리 문맥에서 비어 있지 않은 값은 모두 ``True``이다
논리 문맥에서 빈 값은 ``False``이다
주석은 빈칸이나 탭이 앞에 있을 수 있는,
#문자로 시작하는 줄이다.
연산자 우선순위
연산자 우선순위(평가 순서)는 가장 높은 것(가장 먼저 평가)부터 가장 낮은 것(가장 나중에 평가)까지 다음과 같다:
함수 호출, 상수, 괄호로 묶인 식, 문장 식, 할당 식, 필드 참조.
단항 플러스(
+)와 마이너스(-). 이 연산자들은 오른쪽에서 왼쪽으로 평가된다.이 연산자들과 다른 모든 산술 연산자는 식의 결과에 소수 부분이 없으면 정수를 반환한다. 예를 들어 식이 ``3.0``을 반환하면 ``3``으로 바뀐다.
곱하기(
*)와 나누기(/). 이 연산자들은 결합법칙이 적용되며 왼쪽에서 오른쪽으로 평가된다. 평가 순서를 바꾸고 싶다면 괄호를 사용하라.더하기(
+)와 빼기(-). 이 연산자들은 결합법칙이 적용되며 왼쪽에서 오른쪽으로 평가된다.숫자 및 문자열 비교. 이 연산자들은 비교가 성공하면
'1'``을, 그렇지 않으면 빈 문자열(‘’``)을 반환한다. 비교는 결합적이지 않으므로 ``a < b < c``는 문법 오류이다.문자열 연결(
&).&연산자는 왼쪽 식과 오른쪽 식을 이어 붙인 문자열을 반환한다. 예: ``’aaa’ & ‘bbb’``는 ``’aaabbb’``를 반환한다. 이 연산자는 결합법칙이 적용되며 왼쪽에서 오른쪽으로 평가된다.단항 논리 부정(
!). 이 연산자는 식이 False(빈 문자열로 평가됨)면 ``’1’``을, 그렇지 않으면 ``’’``을 반환한다.논리곱(
&&). 이 연산자는 왼쪽 식과 오른쪽 식이 모두 True이면 ‘1’을, 둘 중 하나라도 False이면 빈 문자열 ``’’``을 반환한다. 결합법칙이 적용되며 왼쪽에서 오른쪽으로 평가되고, `단락 평가 <https://chortle.ccsu.edu/java5/Notes/chap40/ch40_2.html>`_를 수행한다.논리합(
||). 이 연산자는 왼쪽 식이나 오른쪽 식 중 하나라도 True이면 ``’1’``을, 둘 다 False이면 ``’’``을 반환한다. 결합법칙이 적용되며 왼쪽에서 오른쪽으로 평가되고, 단락 평가 <https://chortle.ccsu.edu/java5/Notes/chap40/ch40_2.html>`_를 수행한다. 이는 `포괄적 or`이므로 왼쪽과 오른쪽 식이 모두 True여도 `’1’``을 반환한다.
필드 참조
field_reference``는 ``$ 또는 $$ 뒤에 오는 lookup name으로 지정된 메타데이터 필드의 값을 평가한다. $ 사용은 field 함수를 사용하는 것과 같다. $$ 사용은 raw_field 함수를 사용하는 것과 같다. 예:
* $authors ==> field('authors')
* $#genre ==> field('#genre')
* $$pubdate ==> raw_field('pubdate')
* $$#my_int ==> raw_field('#my_int')
If 식
If 식은 먼저 condition``을 평가한다. ``condition``이 True(비어 있지 않은 값)이면 ``then 절의 expression_list``를 평가한다. False이면 ``elif 또는 else 절이 있을 경우 그 안의 expression_list``를 평가한다. ``elif``와 ``else 부분은 선택 사항이다. if, then, elif, else, ``fi``는 예약어이므로 식별자 이름으로 사용할 수 없다. 줄바꿈과 공백은 의미가 통하는 위치라면 어디든 넣을 수 있다. 문법은 다음과 같다:
예:
* 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)
중첩된 if 예제:
program:
if field('series') then
if check_yes_no(field('#mybool'), '', '', '1') then
'yes'
else
'no'
fi
else
'no series'
fi
위에서 말했듯이 ``if``는 값을 생성한다. 즉, 다음 예들은 모두 동일하다:
* 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
예를 들어 다음 프로그램은 책에 시리즈가 있으면 series 열의 값을, 없으면 title 열의 값을 반환한다:
program: field(if field('series') then 'series' else 'title' fi)
For 식
for 식은 값 목록을 순회하면서 한 번에 하나씩 처리한다. list_expression``은 메타데이터 필드 ``lookup name``(예: ``tags 또는 #genre) 또는 값 목록으로 평가되어야 한다. :ref:`ff_range`는 숫자 목록을 생성한다. 결과가 유효한 ``lookup name``이면 해당 필드의 값을 가져오고, 그 필드 형식에 지정된 구분자를 사용한다. 결과가 유효한 ``lookup name``이 아니면 값 목록으로 간주한다. 목록은 쉼표로 분리되어 있다고 가정한다. 문법은 다음과 같다:
예: 이 템플릿은 Genre(#genre)의 각 값에서 첫 번째 계층 이름을 제거하여 새 이름 목록을 만든다:
program:
new_tags = '';
for i in '#genre':
j = re(i, '^.*?\.(.*)$', '\1');
new_tags = list_union(new_tags, j, ',')
rof;
new_tags
원래 Genre가 `History.Military, Science Fiction.Alternate History, ReadMe`라면 템플릿은 `Military, Alternate History, ReadMe`를 반환한다. 이 템플릿을 calibre의 :guilabel:`메타데이터 일괄 편집 -> 검색 및 바꾸기`에서 :guilabel:`검색 대상`을 ``template``으로 설정하여 사용하면, 계층 구조의 첫 번째 수준을 제거하고 그 결과 값을 Genre에 할당할 수 있다.
참고: 이 경우 템플릿의 마지막 줄인 new_tags``는 엄밀히 말해 필요하지 않다. ``for``는 식 목록에서 마지막 top_expression의 값을 반환하기 때문이다. 할당의 값은 그 식의 값이므로 ``for 문의 값은 ``new_tags``에 할당된 값이다.
with 식
with 식은:
``top_expression``을 평가해 얻은 calibre 책 ID(정수)를 가진 책으로 현재 책을 바꾼다.
``expression_list``를 실행한다.
그런 다음 현재 책을 원래 값으로 되돌린다.
with 식은 평가된 expression_list``의 마지막 ``top_expression 결과를 반환하며, 식 목록이 평가되지 않았다면 빈 문자열을 반환한다.
예를 들어 다음 템플릿은 GUI에서 선택된 각 책의 제목 목록을 반환한다:
program:
res = '';
ids = selected_books();
for id in ids:
with id:
res = (if res then res & ', ' fi) & $title
htiw
rof;
res
Return 문
``expression``의 값을 반환한다. 함수 안에서 실행되면 그 값을 호출자에게 반환한다. 가장 바깥 문맥(템플릿)에서 실행되면 템플릿의 값을 해당 식의 값으로 설정하고 템플릿 실행을 종료한다.
함수 정의
템플릿에 반복되는 코드가 있다면 그 코드를 지역 함수로 만들 수 있다. def 키워드가 정의를 시작한다. 그 뒤에 함수 이름, 인수 목록, 그리고 함수 본문의 코드가 온다. 함수 정의는 fed 키워드로 끝난다.
인수는 위치 기반이다. 함수를 호출하면 전달된 인수는 정의된 매개변수와 왼쪽에서 오른쪽으로 대응되며, 해당 인수의 값이 매개변수에 할당된다. 정의된 매개변수보다 많은 인수를 전달하면 오류이다. 매개변수는 ``a = 25``처럼 기본값을 가질 수 있다. 그 매개변수에 인수가 전달되지 않으면 기본값이 사용되고, 그렇지 않으면 빈 문자열이 설정된다.
지역 함수 안에서는 return 문을 사용할 수 있다.
함수는 사용하기 전에 정의되어 있어야 한다.
예: 이 템플릿은 일 수를 기준으로 대략적인 기간을 연, 월, 일 단위로 계산한다. 함수 to_plural()``은 계산된 값을 서식화한다. 이 예에서는 ``& 연산자도 사용한다:
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')
관계 연산자
관계 연산자는 비교가 참이면 '1'``을, 그렇지 않으면 빈 문자열(‘’``)을 반환한다.
관계 연산자는 문자열 비교와 숫자 비교 두 종류가 있다.
문자열 비교는 사전식 순서를 사용하며 대소문자를 구분하지 않는다. 지원되는 문자열 비교 연산자는 ==, !=, <, <=, >, >=, in, inlist, inlist_field``이다. ``in, inlist, inlist_field 연산자에서는 왼쪽 식의 결과를 정규식 패턴으로 해석한다. 왼쪽 정규식이 오른쪽 식의 값과 일치하면 참이다. 정규식은 대소문자를 구분하지 않는다.
inlist 연산자는 왼쪽 정규식이 오른쪽 목록의 항목 중 하나라도 일치하면 참이다. 이 목록의 항목은 쉼표로 구분된다. inlist_field 연산자는 오른쪽 식이 가리키는 필드(열)의 항목 중 하나라도 왼쪽 정규식과 일치하면 참이며, 필드에 정의된 구분자를 사용한다. 참고로 ``inlist_field``는 오른쪽 식이 필드 이름으로 평가되어야 하지만, ``inlist``는 단순 문자열 목록을 기대한다.
숫자 비교 연산자는 ==#, !=#, <#, <=#, >#, ``>=#``이다. 왼쪽과 오른쪽 식은 숫자 값으로 평가되어야 한다. 단, 두 가지 예외가 있다. 문자열 값 “None”(정의되지 않은 필드)과 빈 문자열은 모두 값 0으로 평가된다.
예:
program: field('series') == 'foo'는 책의 시리즈가 foo`이면 `’1’``을, 그렇지 않으면 ``’’``을 반환한다.
program: 'f.o' in field('series')는 책의 시리즈가 정규식 ``f.o``(예: foo, Off Onyx 등)와 일치하면 ``’1’``을, 그렇지 않으면 ``’’``을 반환한다.
program: 'science' inlist $#genre는 책의 장르 값 중 하나라도 정규식 ``science``(예: Science, History of Science, Science Fiction 등)와 일치하면 ``’1’``을, 그렇지 않으면 ``’’``을 반환한다.
program: '^science$' inlist $#genre는 책의 장르 중 하나라도 정규식 ``^science$``와 정확히 일치하면(예: Science) ``’1’``을, 그렇지 않으면 ``’’``을 반환한다. `History of Science`와 `Science Fiction`은 일치하지 않는다.
program: 'asimov' inlist $authors는 저자 중 하나라도 정규식 ``asimov``와 일치하면(예: Asimov, Isaac 또는 Isaac Asimov) ``’1’``을, 그렇지 않으면 ``’’``을 반환한다.
program: 'asimov' inlist_field 'authors'는 저자 중 하나라도 정규식 ``asimov``와 일치하면(예: Asimov, Isaac 또는 Isaac Asimov) ``’1’``을, 그렇지 않으면 ``’’``을 반환한다.
program: 'asimov$' inlist_field 'authors'는 저자 중 하나라도 정규식asimov$``와 일치하면(예: `Isaac Asimov`) ``'1'``을, 그렇지 않으면 ``''``을 반환한다. 정규식의 ``$앵커 때문에 `Asimov, Isaac`에는 일치하지 않는다.
program: if field('series') != 'foo' then 'bar' else 'mumble' fi는 책의 시리즈가 foo`가 아니면 `’bar’``를 반환한다. 그렇지 않으면 ``’mumble’``을 반환한다.
program: if field('series') == 'foo' || field('series') == '1632' then 'yes' else 'no' fi는 시리즈가 foo 또는 1632`이면 `’yes’``를, 그렇지 않으면 ``’no’``를 반환한다.
program: if '^(foo|1632)$' in field('series') then 'yes' else 'no' fi는 시리즈가 foo 또는 1632`이면 `’yes’``를, 그렇지 않으면 ``’no’``를 반환한다.
program: if 11 > 2 then 'yes' else 'no' fi는>연산자가 사전식 비교를 수행하므로 ``’no’``를 반환한다.
program: if 11 ># 2 then 'yes' else 'no' fi는>#연산자가 숫자 비교를 수행하므로 ``’yes’``를 반환한다.
General Program Mode의 함수
`template language`에 내장된 함수 목록은 :ref:`template_functions_reference`를 참조하라.
참고:
템플릿 식에서 더 복잡한 프로그램 사용하기 - Template Program Mode¶
Template Program Mode`(`TPM)는 General Program Mode <general_mode>`와 :ref:`Single Function Mode <single_mode>`를 결합한 형태이다. `TPM`은 다른 메타데이터 필드를 참조하고, 중첩 함수를 사용하고, 변수를 수정하고, 산술 연산을 할 수 있다는 점에서 Single Function Mode와 다르다. `General Program Mode`와는 템플릿이 ``{` 와 } 사이에 들어가며 ``program:``이라는 단어로 시작하지 않는다는 점이 다르다. 템플릿의 프로그램 부분은 다음과 같이 구문 분석된다:
예: 책에 시리즈가 있으면 시리즈를 표시하고, 없으면 사용자 정의 필드 #genre 값을 표시하는 템플릿을 원한다고 하자. :ref:`Single Function Mode <single_mode>`에서는 템플릿 식 안에서 다른 메타데이터 필드를 참조할 수 없기 때문에 이를 할 수 없다. `TPM`에서는 가능하며, 다음 식이 그 예이다:
{series:'ifempty($, $#genre)'}
이 예는 여러 가지를 보여 준다:
식이 ``:’``로 시작하고 ``’}``로 끝나면 `TPM`이 사용된다. 그 외의 경우는 :ref:`Single Function Mode <single_mode>`로 간주된다.
템플릿에 접두사와 접미사가 있으면 식은 접두사의 구분자인 ``|``가 붙은 ``’|``로 끝난다. 예:
{series:'ifempty($, $#genre)'|prefix | suffix}
함수에는 모든 인수를 제공해야 한다. 예를 들어 표준 내장 함수에는 초기 매개변수 ``value``를 전달해야 한다.
변수
$``는 ``value인수로 사용할 수 있으며, 여기서는 템플릿에 지정된 필드 ``series``의 값을 뜻한다.식 내부에서는 공백이 무시되므로 어디에든 사용할 수 있다.
TPM`에서 문자열 리터럴 안에 ``{` 와 } 문자를 사용하면 템플릿 처리기가 이를 문자 대신 템플릿 식 경계로 해석하려 하므로 오류나 예상치 못한 결과가 날 수 있다. 경우에 따라 {``를 ``[[``로, ``}``를 `]]`로 바꿀 수 있지만 항상 되는 것은 아니다. 조언: 프로그램에 ``{ 와 } 문자가 포함되어 있다면 `General Program Mode`를 사용하라.
Python Template Mode¶
Python Template Mode(PTM)는 네이티브 Python과 `calibre API <https://manual.calibre-ebook.com/develop.html#api-documentation-for-various-parts-of-calibre>`_를 사용해 템플릿을 작성할 수 있게 해 준다. 가장 유용한 것은 데이터베이스 API이며, 자세한 설명은 이 매뉴얼 범위를 벗어난다. PTM 템플릿은 더 빠르고 더 복잡한 작업을 수행할 수 있지만, calibre API를 사용해 Python 코드를 작성하는 법을 알아야 한다.
PTM 템플릿은 다음으로 시작한다:
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'
보통 오른쪽 클릭으로 여는 문맥 메뉴를 사용해 위 텍스트를 템플릿에 추가할 수 있다. 주석은 의미가 없으므로 제거해도 된다. Python 들여쓰기를 사용해야 한다.
context 객체는 문맥 내용 문자열을 반환하는 ``str(context)``와, 문맥의 속성 이름 목록을 반환하는 ``context.attributes``를 지원한다.
context.funcs 속성을 사용하면 Built-in 및 User 템플릿 함수, 저장된 GPM/Python 템플릿을 호출할 수 있어 코드 안에서 직접 실행할 수 있다. 함수는 이름으로 가져온다. 이름이 Python 키워드와 충돌하면 끝에 밑줄을 하나 붙여라. 예:
context.funcs.list_re_group()
context.funcs.assert_()
다음은 어떤 시리즈의 모든 저자 목록을 만드는 PTM 템플릿 예이다. 이 목록은 다른 열로부터 만들어진 열, 태그처럼 동작`하는 열에 저장된다. 이 값은 :guilabel:`책 정보`에 표시되며 :guilabel:`각 줄에 별도 표시 옵션이 켜져 있다(환경설정 → 모양새 → 책 정보). 이 옵션은 목록이 쉼표로 구분되어 있어야 한다. 이 요구를 만족시키기 위해 템플릿은 저자 이름 안의 쉼표를 세미콜론으로 바꾼 다음, 저자들의 쉼표 구분 목록을 만든다. 이 과정은 함수 ``get_item_names()``의 결과를 authors 필드에 있는 값으로 제한한다:
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))
:guilabel:`책 정보`의 출력은 다음과 같다:
템플릿과 URL¶
템플릿을 사용해 URL을 구성할 수 있다. 여기서는 두 가지 경우를 설명한다:
사용자 정의 열 책 정보 검색 URL
calibre URL 스킴
사용자 정의 열 책 정보 검색 URL
사용자 정의 열을 만들 때 템플릿을 사용해 책 정보`에서 사용할 URL을 지정할 수 있다. 예를 들어 `번역가`용 사용자 정의 열이 있다면 번역가 사이트로 이동하는 URL을 정의할 수 있다. 책 정보 검색 URL은 `Text, Enumerated, Series, Column built from other column 형식 열에 제공할 수 있다.
:guilabel:`책 정보`에서 `검색 템플릿`이 있는 항목을 클릭하면 템플릿이 평가된다. 이때 일반적인 책 메타데이터와 함께 다음 세 개의 추가 필드도 제공된다:
item_value: 클릭한 항목의 값.item_value_quoted: 클릭한 항목의 URL 인코딩된 값. 특수 문자는 URL에서 유효하도록 이스케이프되며 공백은 ``’+’``(플러스) 기호로 바뀐다.item_value_no_plus: 클릭한 항목의 URL 인코딩된 값. 특수 문자는 URL에서 유효하도록 이스케이프되며 공백은 플러스가 아닌 ``%20``으로 바뀐다.
URL을 구성하는 방법은 여러 가지가 있다. 다음 예에서는 Wikipedia를 사용한다.
가장 단순한 방법은 기본 템플릿이다:
https://en.wikipedia.org/w/index.php?search={item_value_encoded}
경우에 따라 더 많은 처리가 필요할 수 있다. 처리 복잡도에 따라 사용할 수 있는 템플릿 함수는 네 가지이다.
make_url
(path, [query_name, query_value]+)– 질의 URL을 구성하는 가장 쉬운 방법입니다. 질의할 웹 사이트와 페이지를 나타내는path와, 질의를 구성하는query_name,query_value쌍을 사용합니다. 일반적으로query_value는 URL 인코딩되어야 합니다. 이 함수는 항상 값을 인코딩하며 공백은 항상'+'기호로 바꿉니다.make_url_extended
(...)– 이 함수는 make_url() 과 비슷하지만 URL 구성 요소를 더 세밀하게 제어할 수 있습니다. URL 의 구성 요소는 다음과 같습니다:scheme:://authority/path?query string.
자세한 내용은 Wikipedia 의 Uniform Resource Locator 문서를 참조하십시오.
이 함수에는 두 가지 형태가 있습니다:
make_url_extended(scheme, authority, path, [query_name, query_value]+)
그리고
make_url_extended(scheme, authority, path, query_string)
query_string
([query_name, query_value, how_to_encode]+)–query_name, query_value, how_to_encode삼중항으로부터 URL 질의 문자열을 구성해 반환합니다. 질의 문자열은query_name=query_value형태의 항목들이 이어진 것이며,query_value는 지정된 방식대로 URL 인코딩됩니다. 각 항목은 ``’&’``(앰퍼샌드) 문자로 구분됩니다.encode_for_url
(value, use_plus)–use_plus설정에 따라 URL 에 사용할 수 있게value를 인코딩해 반환합니다. 값은 먼저 URL 인코딩되며, 이어서use_plus가0이면 공백을'+'로, 아니면%20으로 바꿉니다.
예를 들어 성, 이름 형식으로 이름을 저장하는 사용자 정의 열 Translators`(``#translators`)가 있다고 하자. URL을 만들 때 이 이름을 이름 성 형식으로 바꿔야 할 수 있다. 이때 make_url 함수를 사용할 수 있다:
program: make_url('https://en.wikipedia.org/w/index.php', 'search', swap_around_comma($item_value))
번역가 이름이 `Boy-Żeleński, Tadeusz`라고 가정하면 위 템플릿은 다음 링크를 만든다:
https://en.wikipedia.org/w/index.php?search=Tadeusz+Boy-%C5%BBele%C5%84ski
이제 사람 이름은 이름이 먼저 오고, 공백은 플러스로 바뀌며, 성에 있는 비영어 문자는 URL 인코딩된다는 점에 유의하라.
추가 처리의 복잡도에 따라 make_url_extended, query_string, encode_for_url 함수도 유용할 수 있다.
calibre URL 스킴
Calibre는 calibre 라이브러리를 탐색하기 위한 여러 종류의 URL을 지원한다. 이 절에서는 템플릿을 사용해 일부 URL을 구성하는 방법을 보여 준다. 사용 가능한 URL의 자세한 내용은 :doc:`url_scheme`를 참조하라.
특정 라이브러리로 전환한다. 이 URL의 문법은 다음과 같다:
calibre://switch-library/Library_Name
``Library_Name``은 열고 싶은 calibre 라이브러리의 이름으로 바꿔야 한다. 라이브러리 이름은 창의 제목 표시줄에 표시된다. 이것은 라이브러리의 파일 경로가 아니라 단순한 이름이다. 제목 표시줄에 보이는 대로, 대소문자까지 포함해 정확히 입력해야 한다. 문자 ```(밑줄)는 현재 라이브러리를 뜻한다. 이름에 공백이나 특수 문자가 포함되어 있다면 다음 예와 같이 :ref:`ff_to_hex 함수를 사용해 hex 인코딩해야 한다:
program: strcat('calibre://switch-library/_hex_-', to_hex(current_library_name()))
이 템플릿은 다음 URL을 생성한다:
calibre://switch-library/_hex_-4c6962726172792e746573745f736d616c6c
current_library_name()함수를 실제 라이브러리 이름으로 바꿔 쓸 수도 있다:program: strcat('calibre://switch-library/_hex_-', to_hex('Library.test_small'))
책을 표시하는 링크. 이 링크는 calibre 라이브러리에서 특정 책을 선택한다. 이 URL의 문법은 다음과 같다:
calibre://show-book/Library_Name/book_id
``book id``는 책의 숫자형 calibre ID이며 템플릿에서는 ``$id``로 사용할 수 있다. 위와 마찬가지로 라이브러리 이름은 hex 인코딩이 필요할 수 있다. 예:
program: strcat('calibre://show-book/_hex_-', to_hex(current_library_name()), '/', $id)이 템플릿은 다음 URL을 만든다:
calibre://show-book/_hex_-4c6962726172792e746573745f736d616c6c/1353
책 검색하기. 이 링크는 지정된 calibre 라이브러리에서 책을 검색한다. 이 URL의 문법은 다음과 같다:
calibre://search/Library_Name?q=query calibre://search/Library_Name?eq=hex_encoded_query
`query`는 유효한 calibre 검색 식이면 무엇이든 될 수 있다. 공백이나 특수 문자가 들어간 질의는 반드시 hex 인코딩해야 하며, 실제로는 거의 모두 해당된다. 예를 들어 ‘AA’로 시작하는 계층형 태그를 찾는 calibre 검색 식은 ``tags:”=.AA”``이다. 다음 템플릿은 이 식의 검색 URL을 만든다:
program: strcat('calibre://search/_hex_-', to_hex(current_library_name()), '?eq=', to_hex('tags:"=.AA"'))
결과 URL은 다음과 같다:
calibre://search/_hex_-4c6962726172792e746573745f736d616c6c?eq=746167733a223d2e414122
다음은 strcat 대신 :ref:
ff_make_url_extended함수를 사용해 같은 URL을 만든 예이다:program: make_url_extended('calibre', '', 'search/_hex_-' & to_hex(current_library_name()), 'eq', to_hex('tags:"=.AA"'))
어떤 라이브러리의 특정 책에 대한 책 정보 창을 연다. 이 URL의 문법은 다음과 같다:
calibre://book-details/Library_Name/book_id
예시 템플릿은 다음과 같다:
program: strcat('calibre://book-details/_hex_-', to_hex(current_library_name()), '/', $id)이 템플릿은 다음 URL을 만든다:
calibre://book-details/_hex_-4c6962726172792e746573745f736d616c6c/1353
저자/시리즈 등의 값에 연결된 노트를 연다. 이 URL의 문법은 다음과 같다:
calibre://book-details/Library_Name/Field_Name/id_Item_Id calibre://book-details/Library_Name/Field_Name/hex_Hex_Encoded_Item_Name
Field_Name``은 필드의 lookup name이다. 필드가 사용자 정의 열이면 ``#문자를 밑줄(_)로 바꿔야 한다.Item_Id``는 그 필드 값의 내부 숫자 ID이다. ``Item_Id``를 반환하는 템플릿 함수는 없으므로, 템플릿에서는 보통 두 번째 형식인 ``Hex_Encoded_Item_Name``을 사용한다. 다음은 ``#authtest필드에서 ``Boy-Żeleński, Tadeusz``의 노트를 여는 예시 템플릿이다:program: strcat('calibre://show-note/_hex_-', to_hex(current_library_name()), '/_authtest/hex_', to_hex('Boy-Żeleński, Tadeusz'))
이 템플릿은 다음 URL을 만든다:
calibre://show-note/_hex_-4c6962726172792e746573745f736d616c6c/_authtest/hex_426f792dc5bb656c65c584736b692c205461646575737a
저장된 템플릿¶
:ref:`General Program Mode <general_mode>`와 :ref:`Python Template Mode <python_mode>`는 모두 템플릿을 저장하고 다른 템플릿에서 마치 저장된 함수처럼 그 템플릿을 호출하는 기능을 지원한다. 템플릿은 :guilabel:`환경설정->고급->템플릿 함수`에서 저장한다. 자세한 정보는 해당 대화상자에 나와 있다. 템플릿 호출은 함수 호출과 동일하게 하며, 필요하면 위치 인수를 전달할 수 있다. 인수는 어떤 식이든 될 수 있다. 저장된 템플릿 이름이 ``foo``라고 가정할 때의 호출 예는 다음과 같다:
foo()– 인수 없이 템플릿을 호출한다.foo(if field('series') then field('series_index') else 0 fi)– 책에 ``series``가 있으면 ``series_index``를 전달하고, 그렇지 않으면 값 ``0``을 전달한다.
GPM에서는 arguments 함수를 사용해 저장된 템플릿 호출 시 전달된 인수를 가져온다. 이 함수는 지역 변수를 선언하고 초기화하므로 사실상 매개변수 역할을 한다. 변수는 위치 기반이며, 호출에서 같은 위치에 전달된 매개변수 값을 받는다. 해당 매개변수가 전달되지 않았으면 ``arguments``는 그 변수에 제공된 기본값을 할당한다. 기본값도 없다면 빈 문자열이 설정된다. 예를 들면:
arguments(key, alternate='series')
예, 다시 저장된 템플릿 이름이 ``foo``라고 가정하면:
foo('#myseries')– 인수 ``key``에는 값 ``’myseries’``가 할당되고, 인수 ``alternate``에는 기본값 ``’series’``가 할당된다.foo('series', '#genre')– 변수 ``key``에는 값 ``’series’``가, 변수 ``alternate``에는 값 ``’#genre’``가 할당된다.foo()– 변수 ``key``에는 빈 문자열이, 변수 ``alternate``에는 값 ``’series’``가 할당된다.
PTM에서는 인수가 arguments 매개변수로 전달되며, 이는 문자열 목록이다. 기본값을 지정하는 방법은 없다. arguments 목록 길이를 확인해 인수 개수가 기대한 것과 맞는지 직접 검사해야 한다.
저장된 템플릿을 쉽게 시험하는 방법은 Template tester 대화상자를 사용하는 것이다. 쉽게 접근하려면 환경설정 → 고급 → 키보드 단축키 → Template tester`에서 단축키를 지정하라. ``Stored templates` 대화상자에도 단축키를 지정하면 테스터와 저장된 템플릿 소스 편집 사이를 더 빠르게 오갈 수 있다.
템플릿에 추가 정보 제공하기¶
개발자는 응용프로그램별 책 메타데이터나 프로세서가 수행해야 하는 작업 같은 추가 정보를 템플릿 처리기에 전달하도록 선택할 수 있다. 템플릿은 이 정보에 접근하여 평가 중에 사용할 수 있다.
개발자: 추가 정보를 전달하는 방법
추가 정보는 variable_name: variable_value 쌍을 담은 Python 사전이며, 값은 문자열이어야 한다. 템플릿은 이 사전에 접근하여 ``variable_name``이라는 이름의 지역 변수를 만들고 그 값으로 ``variable_value``를 넣을 수 있다. 사용자는 그 이름을 바꿀 수 없으므로, 다른 템플릿 지역 변수와 충돌하지 않도록 앞에 밑줄을 붙이는 등 안전한 이름을 쓰는 것이 좋다.
이 사전은 이름 있는 매개변수 global_vars=your_dict``를 사용해 템플릿 처리기(``formatter)에 전달된다. 전체 메서드 시그니처는 다음과 같다:
def safe_format(self, fmt, kwargs, error_value, book,
column_name=None, template_cache=None,
strip_results=True, template_functions=None,
global_vars={})
템플릿 작성자: 추가 정보에 접근하는 방법
템플릿에서는 다음 템플릿 함수를 사용해 추가 정보(globals 사전)에 접근한다:
globals(id[=expression] [, id[=expression]]*)
여기서 ``id``는 합법적인 변수 이름이면 무엇이든 된다. 이 함수는 개발자가 제공한 추가 정보에 해당 이름이 있는지 확인한다. 있다면 제공된 값을 같은 이름의 템플릿 지역 변수에 할당한다. 그 이름이 추가 정보에 없고 ``expression``이 제공되면 그 식을 평가한 결과를 지역 변수에 할당한다. 값도 식도 없으면 이 함수는 지역 변수에 빈 문자열을 할당한다.
템플릿은 다음 템플릿 함수를 사용해 globals 사전에 값을 설정할 수 있다:
set_globals(id[=expression] [, id[=expression]]*)
이 함수는 globals 사전에 id:value 키:값 쌍을 설정한다. 여기서 ``value``는 템플릿 지역 변수 ``id``의 값이다. 해당 지역 변수가 존재하지 않으면 ``expression``을 평가한 결과가 ``value``로 사용된다.
모드 간 차이점에 대한 참고¶
세 가지 프로그램 모드, 즉 Single Function Mode <single_mode>`(SFM), :ref:`Template Program Mode <template_mode>`(`TPM), General Program Mode <general_mode>`(`GPM)는 서로 다르게 동작한다. SFM은 ‘단순함’을 목표로 하기 때문에 프로그래밍 언어의 많은 요소를 숨긴다.
차이점:
SFM에서는 열의 값이 템플릿에 포함된 함수의 첫 번째 인수로 항상 ‘보이지 않게’ 전달된다.
SFM은 변수와 문자열의 차이를 지원하지 않으며, 모든 값은 문자열이다.
다음 SFM 템플릿은 시리즈 이름 또는 문자열 “no series”를 반환한다:
{series:ifempty(no series)}
`TPM`에서 이에 해당하는 템플릿은 다음과 같다
{series:'ifempty($, 'no series')'}
`GPM`에서 이에 해당하는 템플릿은 다음과 같다:
program: ifempty(field('series'), 'no series')
ifempty``의 첫 번째 인수는 ``series필드의 값이다. 두 번째 인수는 문자열 ``no series``이다. SFM에서는 첫 번째 인수, 즉 필드 값이 자동으로 전달된다(보이지 않는 인수).booksize()및 ``current_library_name()``처럼 인수를 받지 않는 템플릿 함수도 여럿 있다. 하지만 ‘보이지 않는 인수’ 때문에 이런 함수는 SFM에서 사용할 수 없다.한 함수가 다른 함수를 호출해 인수를 계산하는 중첩 함수는 SFM에서 사용할 수 없다. 예를 들어 시리즈 값을 대문자로 바꾼 뒤 처음 5글자만 반환하려는 다음 템플릿은 SFM에서 동작하지 않는다:
{series:uppercase(substr(0,5))}
`TPM`과 `GPM`은 중첩 함수를 지원한다. 위의 템플릿을 `TPM`으로 쓰면 다음과 같다:
{series:'uppercase(substr($, 0,5))'}
`GPM`에서는 다음과 같다:
program: uppercase(substr(field('series'), 0,5))
위 Template Program Mode 절에서 언급했듯이, TPM 문자열 리터럴 안에서
{와}문자를 사용하면 템플릿 처리기가 이를 문자 대신 템플릿 경계로 취급하려 하기 때문에 오류나 예상치 못한 결과가 날 수 있다. 경우에 따라{``를 ``[[``로, ``}``를 `]]`로 바꿀 수 있지만 항상 되는 것은 아니다. 일반적으로 프로그램에 ``{와}문자가 포함되어 있다면 `General Program Mode`를 사용해야 한다.
사용자 정의 Python 템플릿 함수¶
사용자는 템플릿 처리기에 자신만의 Python 함수를 추가할 수 있다. 이런 함수는 세 가지 템플릿 프로그래밍 모드 어디에서나 사용할 수 있다. 함수는 :guilabel:`환경설정 -> 고급 -> 템플릿 함수`로 가서 추가한다. 해당 대화상자에 지침이 표시된다. 비슷한 목적으로 `Python Templates`를 사용할 수도 있다. 사용자 정의 함수 호출은 Python 템플릿 호출보다 빠르므로, 작업 복잡도에 따라 더 효율적일 수 있다.
서로 다른 문맥에서 템플릿을 사용할 때의 특별 참고사항¶
GUI에서(다른 열로부터 만들어진 열 및 템플릿 검색):
GPM 템플릿은 이전과 같이 동작한다.
Python 템플릿은 calibre 데이터베이스에 완전히 접근할 수 있다.
아이콘 규칙에서:
아이콘 규칙 템플릿에는 책 데이터가 없으므로 format_date_field, list_count_field, check_yes_no 같은 필드 기반 함수는 동작하지 않는다.
콘텐츠 서버에서:
템플릿은 새 API에는 접근할 수 있지만 이전 API(LibraryDatabase)에는 접근할 수 없다.
위 이유로 인해 다음 formatter 함수들은 GPM 템플릿(합성 열, 아이콘 규칙 등)에서 정상 동작이 보장되지 않으므로 콘텐츠 서버를 사용할 경우 피해야 한다:
저장/전송 템플릿에 대한 특별 참고사항¶
템플릿을 디스크에 저장 또는 기기로 보내기 템플릿으로 사용할 때는 특별한 처리가 적용된다. 필드 값은 슬래시를 포함해 파일 시스템에서 특별한 의미를 가진 문자를 밑줄로 바꾸는 방식으로 정리된다. 즉, 필드 텍스트로 폴더를 만들 수 없다. 그러나 접두사/접미사 문자열의 슬래시는 바뀌지 않으므로, 이 문자열에 슬래시가 있으면 폴더가 생성된다. 이 점을 이용하면 시리즈 정보나 사용자 정의 열 값을 기준으로 가변 깊이의 폴더 구조를 만들 수 있다.
예를 들어 `series/series_index - title`이라는 폴더 구조를 원한다고 하자. 단, 시리즈가 없으면 제목이 최상위 폴더에 있어야 한다. 이를 위한 템플릿은 다음과 같다:
{series:||/}{series_index:|| - }{title}
슬래시와 하이픈은 series가 비어 있지 않을 때만 나타난다.
lookup 함수를 사용하면 더 복잡한 처리도 가능하다. 예를 들어 책에 시리즈가 있으면 series/series index - title.fmt 구조를 원하고, 시리즈가 없으면 genre/author_sort/title.fmt 구조를 원한다고 하자. 장르도 없으면 ‘Unknown’을 사용하고 싶다. 즉, series 값에 따라 완전히 다른 두 경로를 사용하고 싶은 것이다.
이를 위해 우리는:
``{series}/{series_index} - {title}``를 담는 합성 필드(lookup name은 #aa)를 만든다. 시리즈가 비어 있지 않으면 이 템플릿은 `series/series_index - title`을 만든다.
``{#genre:ifempty(Unknown)}/{author_sort}/{title}``를 담는 합성 필드(lookup name은 #bb)를 만든다. 이 템플릿은 `genre/author_sort/title`을 만들며, 비어 있는 장르는 `Unknown`으로 대체된다.
저장 템플릿을 ``{series:lookup(.,#aa,#bb)}``로 설정한다. 이 템플릿은 series가 비어 있지 않으면 합성 필드 ``#aa``를, 비어 있으면 합성 필드 ``#bb``를 선택한다. 따라서 `series`가 비어 있는지 여부에 따라 완전히 다른 두 저장 경로를 가지게 된다.
팁¶
Template Tester를 사용해 템플릿을 시험하라. 라이브러리의 책 문맥 메뉴에 테스터를 추가하거나 키보드 단축키를 지정해 두면 편리하다.
템플릿은 원하는 템플릿으로 만들어진 합성 열을 참조함으로써 다른 템플릿을 사용할 수 있다. 또는 Stored Templates를 사용할 수도 있다.
플러그보드에서는 특수 템플릿 ``{}``를 사용해 필드를 빈 값(또는 빈 값에 해당하는 값)으로 설정할 수 있다. 이 템플릿은 항상 빈 문자열로 평가된다.
위에서 설명한, 값이 0이어도 숫자를 표시하는 기법은 표준 필드 series_index에도 적용된다.
