Тестирование последовательных вызовов среды

Тестирование последовательных вызовов среды

Я использую Beamer для создания слайдов для своего курса статистики, и теперь у меня очень хорошая установка, которая генерирует вывод, похожий на PowerPoint (см. вопрос:Используйте Beamer для размещения 3 слайдов на странице с примечаниями рядом (как в PowerPoint)).

Чтобы эта система работала, мне нужно определение для заметок, связанных со слайдом для каждого слайда, иначе заметки будут рассинхронизированы со слайдами. Вероятно, есть лучший способ определить определение заметки «по умолчанию» для слайда, чтобы они никогда не могли рассинхронизироваться, но это выходит за рамки моих возможностей в латексе, а среда достаточно сложна, так что размещение MWE для этого будет сложным (для меня).

Вместо этого я хочу хотя бы поймать ошибку, что для слайда не определены заметки. Самый простой способ, который я могу придумать, сводится к MWE, показанному ниже:

\documentclass[10pt]{article}

\newcounter{mypagecount}
\setcounter{mypagecount}{1}

\newcommand\incpagecount{
  \stepcounter{mypagecount}
}
\newcommand\getpagecount{
  \themypagecount
}

\newenvironment{mypage}[1]{%
Parameter: #1 Expected: \getpagecount Body :}{ \incpagecount \\ }

\begin{document}

\begin{mypage}{1} foo \end{mypage}
\begin{mypage}{2} foo \end{mypage}
\begin{mypage}{4} foo \end{mypage}
\begin{mypage}{5} foo \end{mypage}

\end{document}

ВОПРОС: Как заставить latex выдавать ошибку, когда он обнаруживает, что не было вызова для mypage {3}? Для программистов на C было бы здорово показать, как использовать утверждение в стиле C, что параметр не равен ожидаемому значению!

Спасибо всем.

решение1

Нет assert. Даже нет !=. Также есть \if, \ifdim, \ifx, \ifcase, \@ifundefined, \@ifl@adedи т. д. См. TeXbook (Knuth) и source2e.pdf (CTAN).

Обратите внимание, что локальные определения не будут доступны вне среды. К счастью, операции счетчика используют глобальные версии. \global\letи \xdefмогут использоваться, но \setlengthи \renewcommandне могут.

\documentclass[10pt]{article}

\newcounter{mypagecount}
\setcounter{mypagecount}{1}

\newcommand\incpagecount{%
  \stepcounter{mypagecount}%
}
\newcommand\getpagecount{% redundant
  \themypagecount
}

\newenvironment{mypage}[1]{%
\ifnum\value{mypagecount}=#1\relax
\else
  \errmessage{Parameter: #1 Expected: \getpagecount}%
  \setcounter{mypagecount}{#1}%
\fi
\noindent Body :}%
{ \incpagecount \\ }

\begin{document}

\begin{mypage}{1} foo \end{mypage}
\begin{mypage}{2} foo \end{mypage}
\begin{mypage}{4} foo \end{mypage}
\begin{mypage}{5} foo \end{mypage}

\end{document}

решение2

Я предлагаю другое решение. В настоящее время это проверка концепции. В частности, она даст сбой, если вы передадите какие-либо параметры, кроме labelсреды frame. Я думаю, это можно исправить, но это усложнит ситуацию.

Идея состоит в том, чтобы включить слайды в раздаточный материал другим способом. Это использует beamerarticleпакет Beamer, labelопцию для frameокружений и \includeslideмакрос. Он также использует xcoffins(потому что я слишком устал возиться с minipages и т. п.) и environ.

Рабочий процесс:

  • 3 файла, 2 из которых представляют собой чрезвычайно простые оболочки, которые являются входными данными для третьего.

  • Третий файл не содержит \documentclass, но содержит и слайды, и заметки. Предположим, что это <main file name>.tex.

  • Слайды идут в frameокружении, как обычно. Они помечены с помощью опции label.

  • Примечания идут в annotокружениях. Для них требуется аргумент, дающий метку для соответствующего слайда. (Если бы вы ссылались на слайд в обычном режиме, это был бы аргумент, который вы бы указали \ref{}.) Необязательный аргумент можно использовать для переопределения настроек, используемых при включении слайда.

  • Первая оболочка скомпилирована для создания слайдов. Я назвал ее <main file name>-beamer.tex. Содержимое этого файла должно быть

    \pdfminorversion=7% comment this out if not using pdftex
    \documentclass[ignorenonframetext]{beamer}
    \input{<main file name>}% substitute appropriately here
    

    Это должно быть скомпилированопервый.

  • Вторая оболочка компилируется для создания раздаточных материалов. Я назвал ее так, <main file name>-article.texпотому что использовал articleкласс и режим Beamer article. Содержимое этого файла должно быть

    \pdfminorversion=7% comment this out if not using pdftex
    \documentclass{article}% adjust if you prefer a different class
    \usepackage{beamerarticle,graphicx}
    \setjobnamebeamerversion{<main file name>-beamer}% substitute appropriately here
    \input{<main file name>}% substitute appropriately here
    

    Это должно быть скомпилировановторой.

Затем в <main file name>.tex, вы помещаете остальную часть вашей преамбулы и documentтела. Я поместил большую часть пользовательского материала в преамбулу здесь, ограничивая его режимом Beamer article, но вы можете переместить это в оболочку раздаточного материала, если хотите.

% \jobname.tex = <main file name>.tex
\mode<article>
{

Это будет выполнено только в articleрежиме.

  \usepackage{xcoffins,environ,geometry,calc,pgf}

xcoffins, environ, pgfи calcтребуются. geometryтолько что избавился от плохих ящиков.

Сначала несколько новых длин, которые нам понадобятся позже.

  \newlength\annotsep
  \setlength\annotsep{.5em}% set the horizontal separation of frames and annotations
  \newlength\frmwd
  \AtBeginDocument{%
    \setlength\frmwd{.5\linewidth-.5\annotsep-2\fboxsep-2\fboxrule}%
  }

И пара гробов.

  \NewCoffin\AnnotCoffin
  \NewCoffin\FrameCoffin

Теперь мы определяем annotсреду, но используем , \NewEnvironа не , \newenvironmentпотому что мы хотим поместить весь контент в гроб, и это показалось нам самым простым. (Я пытался избежать expl3синтаксиса здесь.)

  \NewEnviron{annot}[2][]{%
    \edef\tempa{\extractedref}\edef\tempb{#2}%
    \ifx\tempa\tempb\relax
    \else\outputempty\fi\xdef\extractedref{}%

Это проверяет, есть ли какие-либо кадры, для которых мы не вставили слайд, кроме того, что для этой аннотации. Если был помечен, frameкоторому этот набор заметок не соответствует, мы предполагаем, что у этого кадра нет заметок, и выводим его с пустым пространством справа.

Теперь мы устанавливаем наш первый гроб, \FrameCoffinс рамкой-копией соответствующего слайда (то есть того, на который мы ссылались, используя annotобязательный аргумент среды).

    \SetVerticalCoffin\FrameCoffin{.5\linewidth-.5\annotsep}{%
      \fbox{\includeslide[width=\frmwd,#1]{#2}}% depending on theme, remove frame if not required
    }%

Теперь мы устанавливаем второй гроб — \AnnotCoffinдля заметок.

    \SetVerticalCoffin\AnnotCoffin{.5\linewidth-.5\annotsep}{%
      \BODY
    }%

Соединяем гробы наверху, сдвигая узлы немного поперек и вниз.

    \JoinCoffins\FrameCoffin[t,r]\AnnotCoffin[t,l](\annotsep,-.5\baselineskip)

Наберите текст на гробах и оставьте немного свободного места по вертикали, чтобы слайды равномерно располагались на странице.

    \TypesetCoffin\FrameCoffin
    \medskip\vfill\par
  }
  \usepackage{kantlipsum}

Этот пакет просто для примера. Не загружайте его в ваш настоящий документ, если только вы не набираете соответствующие отрывки из Канта и вас не смущает, что перевод, вероятно, устарел.

Пара новых команд.

  \newcommand\extractref{}
  \newcommand\extractedref{}

Определите один из них как вспомогательный макрос.

  \def\extractref label=#1\null{#1}

Это изменяет определение framein articlemode. Обычно Beamer верстает frameсодержимое во всех режимах. Однако здесь мы этого не хотим. Мы определяем его так, чтобы он принимал один необязательный аргумент. Все остальное исчезнет. Но если есть необязательный первый аргумент и он не пустой, мы предположим, что это label=<key for label>и извлечем эту ссылку.

  \RenewEnviron{frame}[1][]{%
    \edef\tempa{#1}\edef\tempb{}%
    \ifx\tempa\tempb\relax
    \else
      \outputempty

Если макрос, отслеживающий отслеживание, \extractedrefне пустой, то был слайд без соответствующего набора заметок, поэтому мы предполагаем, что у слайда нет заметок, и выводим этот слайд с пустым набором заметок справа.

      \xdef\extractedref{\extractref #1\null}%

Для текущего frameмы ничего не набираем. Мы просто извлекаем и сохраняем ссылку в \extractedref.

    \fi
  }

Теперь для макроса, который выводит frames без аннотаций. Это используется переопределенными frameи annotокружениями.

  \newcommand\outputempty{%
    \edef\tempb{}%
    \edef\tempa{\extractedref}%
    \ifx\tempa\tempb\relax
    \else

Здесь гробы не нужны, но мы выводим слайд, используя конфигурацию по умолчанию, и оставляем тот же вертикальный интервал, чтобы слайды равномерно распределялись по странице.

      \fbox{\includeslide[width=\frmwd]{\extractedref}}%
      \medskip\vfill\par
    \fi
  }
}

Я полагаю, что вам не нужен отступ абзаца здесь. Вы можете рассмотреть возможность использования пакета parskip, но это может не иметь значения, в зависимости от содержания ваших заметок.

  \setlength\parindent{0pt}

Если последний frameпомечен, но не имеет примечаний, нам нужно убедиться, что он попал в раздаточный материал. Еще один \outputemptyдолжен это сделать.

  \AtEndDocument{\outputempty}

Вот и вся конфигурация. Теперь документ.

\begin{document}

вот кадр, обозначенный frame-a.

\begin{frame}[label=frame-a]{A Frame}%
  \includegraphics[height=.75\textheight,width=\textwidth,keepaspectratio]{example-image-a}
\end{frame}

Вот заметки для frame-a.

\begin{annot}{frame-a}
  Not much to say about image A.
\end{annot}

Аналогично для frame-bи frame-c.

\begin{frame}[label=frame-b]{B Frame}%
  \includegraphics[height=.75\textheight,width=\textwidth,keepaspectratio]{example-image-b}
\end{frame}
\begin{annot}{frame-b}
  Not much to say about image b.
\end{annot}

\begin{frame}[label=frame-c]{C Frame}%
  \includegraphics[height=.75\textheight,width=\textwidth,keepaspectratio]{example-image-c}
\end{frame}
\begin{annot}{frame-c}
  Not much to say about image C.
\end{annot}

Это создаст страницу с geometryмакетом по умолчанию.

Вот frame-another. Здесь нет примечаний, поэтому нет annotпродолжения.

\begin{frame}[label=frame-another]{Another Frame}%
  \includegraphics[height=.75\textheight,width=\textwidth,keepaspectratio]{example-image}
\end{frame}

В articleрежиме следующий кадр будет frame-anotherвыведен, поскольку мы предполагаем, что для него нет заметок frame. У меня закончились и надоели изображения MWE, так что вот вам крутая альтернатива.

\begin{frame}[label=frame-tiger]{Tiger Frame}%
  \includegraphics[height=.75\textheight,width=\textwidth,keepaspectratio]{tiger}
\end{frame}
\begin{annot}{frame-tiger}
  This frame shows a large, wild cat.
  Well, what it actually shows is a small picture of a wild cat, but you are meant to infer that it represents a larger reality.
\end{annot}

В следующем frameбудет очень длинная заметка, поэтому она будет на своей странице. Здесь немного меньше рева, но безопасность в числах, возможно.

\begin{frame}[label=frame-cats]{Cats Frame}%
  \includegraphics[height=.75\textheight,width=\textwidth,keepaspectratio]{cathod}
\end{frame}
\begin{annot}{frame-cats}
  \kant[1-2]
\end{annot}

\begin{frame}[label=frame-which]{Which Frame?}%
 \includegraphics[height=.75\textheight,width=\textwidth,keepaspectratio]{cauldron}
\end{frame}
\begin{annot}{frame-which}
  This frame includes a pun, a cauldron and a question.
  More accurately, it includes a pun, a depiction of a cauldron and a question mark.
\end{annot}

И последнее, незаметное frame, чтобы убедиться, что финал \outputemptyсработает.

\begin{frame}[label=frame-gadael]
  \includegraphics[width=\textwidth]{cath-gadael-chartref}
\end{frame}

\end{document}

Слайды:

слайды

Раздаточный материал/примечания:

раздаточный материал с примечаниями

Полный код (требуется замена имен файлов, где указано):

\begin{filecontents}{\jobname-beamer.tex}
\documentclass[ignorenonframetext]{beamer}
\input{<main file name>}% substitute \jobname or whatever here
\end{filecontents}
\begin{filecontents}{\jobname-article.tex}
\documentclass{article}
\usepackage{beamerarticle,graphicx}
\setjobnamebeamerversion{<main file name>-beamer}% substitute \jobname or whatever here
\input{<main file name>}% substitute \jobname or whatever here
\end{filecontents}

% \jobname.tex = <main file name>.tex
\mode<article>
{
  \usepackage{xcoffins,environ,geometry,calc,pgf}
  \newlength\annotsep
  \setlength\annotsep{.5em}% set the horizontal separation of frames and annotations
  \newlength\frmwd
  \AtBeginDocument{%
    \setlength\frmwd{.5\linewidth-.5\annotsep-2\fboxsep-2\fboxrule}%
  }
  \NewCoffin\AnnotCoffin
  \NewCoffin\FrameCoffin
  \NewEnviron{annot}[2][]{%
    \edef\tempa{\extractedref}\edef\tempb{#2}%
    \ifx\tempa\tempb\relax
    \else\outputempty\fi\xdef\extractedref{}%
    \SetVerticalCoffin\FrameCoffin{.5\linewidth-.5\annotsep}{%
      \fbox{\includeslide[width=\frmwd,#1]{#2}}% depending on theme, remove frame if not required
    }%
    \SetVerticalCoffin\AnnotCoffin{.5\linewidth-.5\annotsep}{%
      \BODY
    }%
    \JoinCoffins\FrameCoffin[t,r]\AnnotCoffin[t,l](\annotsep,-.5\baselineskip)
    \TypesetCoffin\FrameCoffin
    \medskip\vfill\par
  }
  \usepackage{kantlipsum}
  \newcommand\extractref{}
  \newcommand\extractedref{}
  \def\extractref label=#1\null{#1}
  \RenewEnviron{frame}[1][]{%
    \edef\tempa{#1}\edef\tempb{}%
    \ifx\tempa\tempb\relax
    \else
      \outputempty
      \xdef\extractedref{\extractref #1\null}%
    \fi
  }
  \newcommand\outputempty{%
    \edef\tempb{}%
    \edef\tempa{\extractedref}%
    \ifx\tempa\tempb\relax
    \else
      \fbox{\includeslide[width=\frmwd]{\extractedref}}%
      \medskip\vfill\par
    \fi
  }
  \setlength\parindent{0pt}
  \AtEndDocument{\outputempty}
}
\begin{document}
\begin{frame}[label=frame-a]{A Frame}%
  \includegraphics[height=.75\textheight,width=\textwidth,keepaspectratio]{example-image-a}
\end{frame}
\begin{annot}{frame-a}
  Not much to say about image A.
\end{annot}

\begin{frame}[label=frame-b]{B Frame}%
  \includegraphics[height=.75\textheight,width=\textwidth,keepaspectratio]{example-image-b}
\end{frame}
\begin{annot}{frame-b}
  Not much to say about image b.
\end{annot}

\begin{frame}[label=frame-c]{C Frame}%
  \includegraphics[height=.75\textheight,width=\textwidth,keepaspectratio]{example-image-c}
\end{frame}
\begin{annot}{frame-c}
  Not much to say about image C.
\end{annot}

\begin{frame}[label=frame-another]{Another Frame}%
  \includegraphics[height=.75\textheight,width=\textwidth,keepaspectratio]{example-image}
\end{frame}

\begin{frame}[label=frame-tiger]{Tiger Frame}%
  \includegraphics[height=.75\textheight,width=\textwidth,keepaspectratio]{tiger}
\end{frame}
\begin{annot}{frame-tiger}
  This frame shows a large, wild cat.
  Well, what it actually shows is a small picture of a wild cat, but you are meant to infer that it represents a larger reality.
\end{annot}

\begin{frame}[label=frame-cats]{Cats Frame}%
  \includegraphics[height=.75\textheight,width=\textwidth,keepaspectratio]{cathod}
\end{frame}
\begin{annot}{frame-cats}
  \kant[1-2]
\end{annot}

\begin{frame}[label=frame-which]{Which Frame?}%
 \includegraphics[height=.75\textheight,width=\textwidth,keepaspectratio]{cauldron}
\end{frame}
\begin{annot}{frame-which}
  This frame includes a pun, a cauldron and a question.
  More accurately, it includes a pun, a depiction of a cauldron and a question mark.
\end{annot}

\begin{frame}[label=frame-gadael]
  \includegraphics[width=\textwidth]{cath-gadael-chartref}
\end{frame}

\end{document}

Связанный контент