Gerando duas versões em PDF (com base na declaração condicional) do mesmo arquivo tex com arara

Gerando duas versões em PDF (com base na declaração condicional) do mesmo arquivo tex com arara

Dou aulas em cursos universitários e meu objetivo é conseguir gerar dois pdf's do mesmo texarquivo:

  1. Um conjunto de problemas
  2. Um problema definido com soluções

Já faço isso manualmente chamando \newife configurando \soltrueou \solfalseno cabeçalho dependendo se desejo gerar soluções ou não. Então cerco as soluções \ifsole \fipartimos para as corridas. É ótimo porque as edições no conjunto de problemas exigem alterações em apenas um documento, não em dois. O único incômodo é que preciso compilá-lo uma vez, alterar o pdfnome, alterar o cabeçalho de \soltruepara \solfalsee recompilar novamente para obter os dois documentos. Eu gostaria de usar ararapara automatizar isso.

Tenho acompanhado isso excelentecomoem criar uma yamlregra para ararafazer o que quero. No tutorial, o autor (cmhughes) cria uma regra para compilar um texdocumento em dois pdf's, um com uma coluna e outro com duas. Obviamente, minha aplicação é um pouco diferente.

Eu criei a seguinte solutions.yamlregra:

!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

E este é o mytex.texarquivo de teste:

% 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}

Funciona muito bem. Quando executo ararao texarquivo, ele gera dois pdf, um com a solução e outro sem, conforme desejado. Há duas melhorias que gostaria de fazer, mas não sei como implementar:

  1. Como está, atualmente só posso compilar o texarquivo, ararapois o próprio arquivo não contém \soltruenem \solfalsenele. Eu gostaria de poder colocar algo que o definisse se e somente se ainda não estivesse definido, ararapara que eu pudesse compilar isso fora araratambém. Mas não quero substituir araraa configuração de , pois isso anularia o propósito. Alguma ideia?

  2. Atualmente os pdfarquivos gerados são chamados mytexTRUE.pdf(com soluções) e mytexFALSE.pdf(sem soluções). Prefiro ter algo como mytexS.pdf(com soluções) e mytexQ.pdf(sem soluções). A única maneira que eu poderia pensar de implementar isso seria uma declaração condicional em solutions.yaml, mas pelo que li yamlnão foi realmente projetado para declarações condicionais. Alguma ideia nesta frente?

Se você leu até aqui, você é um verdadeiro herói. Obrigado! Se você pulou o meio, tl; dr: ajude esse estranho a tornar seu fluxo de trabalho um pouco mais eficiente.

Responder1

Uma maneira possível de alcançar a primeira melhoria é explorar \ifdefinedem vez de confiar em um \newif, como no código original. Vamos ver o novo código TeX:

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

O plano aqui é simples: se \solutionflagfor definido, esse trecho de código específico será processado. A ideia é muito parecida com o using \if<flag>, mas não reclama se essa engenhoca não estiver configurada.:)

O código anterior pode ser compilado normalmente com seu mecanismo favorito e não requer arara. Se quiser imprimir as respostas, basta escrever \def\solutionflag{}em algum lugar do preâmbulo e pronto.

Atualizar:esta resposta é atualizada com uma regra para a versão 4.0+. Verifique o histórico de edições de uma versão mais antiga.

Vamos dar uma olhada nesta regra aprimorada:

!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.');
        }
    }

Os argumentos da regra:

  • engine: string, opcional, define o mecanismo. As opções possíveis são pdflatex, e latex. Padrão: .xelatexlualatexpdflatex

  • solutions: booleano natural, opcional, define se a macro da solução será definida no escopo do documento. Padrão: false.

  • name: string, obrigatório, define o nome do documento. O documento será renomeado para este valor. Não há necessidade de especificar a .pdfextensão.

  • options: list, opcional, define a lista de parâmetros adicionais de linha de comando a serem fornecidos ao mecanismo.

Um exemplo de execução:

% 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}

Ao executá-lo com 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

Obtemos a seguinte saída:

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

Outra sugestão interessante é melhorar a semântica do seu documento criando um ambiente para exibir soluções de forma seletiva. O código a seguir foi gentilmente sugerido por David Carlisle (devo US$ 5 a ele):

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

Espero que ajude!:)

informação relacionada