arara を使用して同じ tex ファイルから 2 つの pdf バージョン (条件文に基づく) を生成する

arara を使用して同じ tex ファイルから 2 つの pdf バージョン (条件文に基づく) を生成する

pdf私は大学で講義をしており、同じファイルから2 つの を出力できるようになることが目標ですtex

  1. 問題集
  2. 解決策のある問題集

私はすでに、 を呼び出し、ソリューションを出力するかどうかに応じてヘッダーにまたは を\newif設定することで、これを手動で行っています。次に、ソリューションを で囲めば、準備完了です。問題セットの編集では、2 つのドキュメントではなく 1 つのドキュメントを変更するだけで済むので、これは素晴らしいことです。唯一の面倒な点は、一度コンパイルして の名前を変更し、ヘッダーを から に変更し、両方のドキュメントを取得するために再度コンパイルする必要があることです。これを自動化するには を使用したいと思います。\soltrue\solfalse\ifsol\fipdf\soltrue\solfalsearara

私はこの素晴らしい方法yamlルールを作成してarara、必要な操作を実行できるようにすることについて。ハウツーでは、著者 (cmhughes) が、texドキュメントを 2 つの列にコンパイルするルールを作成しますpdf。1 つは 1 つの列、もう 1 つは 2 つの列です。明らかに、私のアプリケーションは少し異なります。

次のsolutions.yamlルールを作成しました:

!config
# Make two versions of document depending on if statement "sol"
# author: Shane Auerbach (based on work by Chris Hughes)
# requires arara 3.0+
#
# Sample usage
#
# % arara: solutions
# % arara: solutions: {solutions: true}
# % arara: solutions: {solutions: false}
#
identifier: solutions
name: Solutions
commands: 
- <arara> pdflatex "\newif\ifsol\sol@{trigger}\input{@{file}}" 
- <arara> @{ isWindows( "cmd /c move", "mv" ) } @{getBasename(file)}.pdf @{getBasename(file)}@{trigger.toUpperCase()}.pdf
arguments: 
- identifier: trigger
  flag: <arara> @{parameters.trigger}
  default: false

これはテストmytex.texファイルです:

% arara: solutions:  {trigger: true}
% arara: solutions: {trigger: false}

\documentclass{article}
\begin{document}
Question: What is $2+2$?
\ifsol \begin{quote} \textbf{Solution:} $2+2=3$ \end{quote} \fi
\end{document}

araraうまく動作します。ファイルを実行するとtex、希望どおりにソリューションを含むものとソリューションを含まないものの 2 つが出力されますpdf。改善したい点が 2 つありますが、実装方法がわかりません。

  1. 現状では、ファイル自体に も も含まれていないため、texでのみファイルをコンパイルできます。 によってまだ設定されていない場合に限り を設定するものを挿入して、の外部でもコンパイルできるようにしたいと思います。ただし、 の設定を上書きすることは望ましくありません。そうすると目的が達成されません。何かアイデアはありますか?arara\soltrue\solfalseararaararaarara

  2. 現在、生成されるファイルは(ソリューションあり) および(ソリューションなし) とpdf呼ばれます。 (ソリューションあり) および(ソリューションなし) のようなものを希望します。これを実装する唯一の方法は、 の条件文を使用することですが、私が読んだところによると、は実際には条件文用に設計されていません。この点について何かアイデアはありますか?mytexTRUE.pdfmytexFALSE.pdfmytexS.pdfmytexQ.pdfsolutions.yamlyaml

ここまで読んでくださったあなたは、真のヒーローです。ありがとうございます! 途中まで読み飛ばした方は、要約すると、この見知らぬ人のワークフローをほんの少しだけ効率化できるように手伝ってください。

答え1

最初の改善を実現する方法としては、元のコードのよう\ifdefinedに に頼るのではなく\newif、 を活用することが考えられます。新しい TeX コードを見てみましょう。

\documentclass{article}
\begin{document}
Question: What is $2+2$?
\ifdefined\solutionflag\begin{quote} \textbf{Solution:} $2+2=3$ \end{quote}\fi
\end{document}

ここでの計画は単純明快です。\solutionflagが定義されている場合、その特定のコード抜粋が処理されます。 を使用するのと考え方は非常に似ています\if<flag>が、この仕組みが設定されていない場合でもエラーは発生しません。:)

前のコードは通常、お気に入りのエンジンでコンパイルでき、 は必要ありませんarara。答えを印刷したい場合は、\def\solutionflag{}プリアンブルのどこかに書き込むだけで完了です。

アップデート:この回答はバージョン 4.0 以降のルールで更新されています。古いバージョンの編集履歴を確認してください。

改良されたルールを見てみましょう。

!config
identifier: solutions
name: Solutions
authors:
- A duck
commands:
- name: The engine
  command: >
    @{
        prefix = isTrue(solutions, '\\def\\solutionflag{}', '');
        input = '\\input{' + reference.getName() + '}';
        return getCommand(engine, prefix + input, options);
    }
- name: The renaming procedure
  command: >
    @{
        separator = java.io.File.separator;
        prefix = [];
        if (isUnix()) {
            prefix = [ 'mv' ];
        }
        else {
            prefix = [ 'cmd', '/c', 'move' ];
        }
        parent = reference.getParent(); 
        input = parent + separator + getBasename(reference) + '.pdf';
        output = parent + separator + name + '.pdf';
        return getCommand(prefix, input, output);
    }
arguments:
- identifier: engine
  flag: >
    @{
        if ([ 'pdflatex', 'latex', 'xelatex',
              'lualatex' ].contains(parameters.engine)) {
            return parameters.engine;
        }
        else {
            throwError('The provided engine is not valid');
        }
    }
  default: pdflatex
- identifier: name
  flag: >
    @{
        return parameters.name;
    }
  required: true
- identifier: solutions
  flag: >
    @{
        return isTrue(parameters.solutions);
    }
  default: >
    @{
        return false
    }
- identifier: options
  flag: >
    @{
        if (isList(parameters.options)) {
            return parameters.options;
        }
        else {
            throwError('I was expecting a list of options.');
        }
    }

ルールの引数:

  • engine: 文字列、オプション、エンジンを設定します。可能なオプションは、、、pdflatexおよびです。デフォルト: 。latexxelatexlualatexpdflatex

  • solutions: 自然なブール値、オプション、ソリューション マクロがドキュメント スコープ内で定義されるかどうかを設定します。デフォルト: false

  • name: 文字列、必須、ドキュメント名を設定します。ドキュメントの名前はこの値に変更されます。拡張子を指定する必要はありません.pdf

  • options: リスト (オプション) は、エンジンに提供される追加のコマンド ライン パラメーターのリストを設定します。

実行例:

% arara: solutions: { solutions: true, name: 'answers' }
% arara: solutions: { solutions: false, name: 'questions' }

\documentclass{article}
\begin{document}
Question: What is $2+2$?
\ifdefined\solutionflag\begin{quote} \textbf{Solution:} $2+2=3$ \end{quote}\fi
\end{document}

次のように実行する場合arara:

[paulo@cambridge ~] $ $ arara test.tex 
  __ _ _ __ __ _ _ __ __ _ 
 / _` | '__/ _` | '__/ _` |
| (_| | | | (_| | | | (_| |
 \__,_|_|  \__,_|_|  \__,_|

Processing 'test.tex' (size: 264 bytes, last modified: 03/22/2020
06:54:54), please wait.

(Solutions) The engine .................................. SUCCESS
(Solutions) The renaming procedure ...................... SUCCESS
(Solutions) The engine .................................. SUCCESS
(Solutions) The renaming procedure ...................... SUCCESS

Total: 1.25 seconds

次のような出力が得られます。

[paulo@cambridge ~] $ ls *.pdf
answers.pdf  questions.pdf

もう 1 つの興味深い提案は、ソリューションを選択的に表示する環境を作成して、ドキュメントのセマンティクスを改善することです。次のコードは David Carlisle 氏から提案されたものです (彼に 5 ドルの借りがあります)。

\newenvironment{solution}{\ifdefined\solutionflag\else\setbox0\vbox\fi\bgroup}{‌​\par\egroup}

それが役に立てば幸い!:)

関連情報