如何提取重复的功能(exsheets 解决方法)以使其可重复使用?

如何提取重复的功能(exsheets 解决方法)以使其可重复使用?

在与 Clemens(exsheets 维护者)交谈时,他向我介绍了 Gonzalo Medina 提出的一种解决方法,该方法有助于将逐字和列表代码放入 exsheets 中(克莱门斯的词语选择)问题和解决方案环境。

修复 exsheets 问题和解决方案环境中的 lstlisting

我的问题与上一个链接的解决方案中的可重复部分有关。看到解决方案触发了我编程背景中的 DRY(不要重复自己)规则,并让我想为可重复使用的部分编写功能性替代品。

我该如何提取通用代码,这样我就有了一个新的函数调用(缺乏更好的措辞),我可以始终如一地重复使用,而不必每次都复制(阅读:复制粘贴)迷你盒代码?

MWE(根据提到的问题修改而来)有一个用于问题和解决方案的不同的框。

\documentclass{article}

\usepackage{xcolor}
\usepackage{listings}
\usepackage{exsheets}

\lstset{
frame=single,
xleftmargin=20pt,
numbers=left,
numberstyle=\small,
tabsize=2,
breaklines,
showspaces=false,
showstringspaces=false,
language=C,
basicstyle=\small\ttfamily,
commentstyle=\itshape\color{gray}}


\newsavebox\myboxa
\newsavebox\myboxb

\begin{document}

\begin{lrbox}{\myboxa}\begin{minipage}{\textwidth}
\begin{lstlisting}[]
#include <stdio.h>

int main(int argc, char *argv[]) {
  printf("hello, world\n");
}
\end{lstlisting}
\end{minipage}
\end{lrbox}

\begin{lrbox}{\myboxa}\begin{minipage}{\textwidth}
\begin{lstlisting}[]
#include <stdio.h>

int main(int argc, char *argv[]) {
  printf("hello, world\n");
}
\end{lstlisting}
\end{minipage}
\end{lrbox}

\begin{lrbox}{\myboxb}\begin{minipage}{\textwidth}
\begin{lstlisting}[]
#include <stdio.h>

int main(int argc, char *argv[]) {
  printf("hello, world\n");
  # some more things that had to be done
}
\end{lstlisting}
\end{minipage}
\end{lrbox}


\begin{question}{6}
Pre-example text\par
\noindent\usebox\myboxa
\\Post-example text
\end{question}

\begin{solution}
Pre-solution text\par
\noindent\usebox\myboxb
\\Post-solution text
\end{solution}
\printsolutions 

\end{document}

这将生成:

MWE 示例输出

如果我可以提取下面覆盖部分所示的部分,它将更加有用:

逐字提取

如果我可以提取这些部分并使用以下命令访问它们:

\verbatimquestionsolution{6}{Preexample text}{Code}{Post-example text}{Pre-solution text}{Solution code}{Post-solution text}

或者

\verbatimquestion{6}{Preexample text}{Code}{Post-example text}
\verbatimsolution{Preexample text}{Code}{Post-example text}

(其中一个的输出紧接着另一个的输出。

我通常不会使用解决方案前后的文本,因为人们可以在源代码中的注释中这样做,但为了讨论可重复的部分,我在这里添加了它。

我知道这可能看起来像是一个“过于具体”的用例,但我在这里试图学习的是提取部分(我甚至不确定我在这里使用的术语是否正确),这样我就不会重复自己。这不仅有助于这个特定的例子,也有助于我可能遇到的其他可重复的环境。

有一件事我不知道该怎么做,比如

\newsavebox\myboxa
\newsavebox\myboxb

这是序言中的内容。

任何有关这方面的指导都非常感谢。我应该在这里阅读什么?宏?如何传递多个变量?我看到钩子可用,但我如何让它写入前导码(如果这对于 \newsavebox 命令来说是必要的)?

答案1

更新 2013/10/29

自版本 v0.10 (2013/10/24) 以来,exsheets捆绑了一个新包,exsheets-listings该包是基于先前提出的答案构建的。使用它,两个提供的环境的语法与下面的代码略有不同:

\begin{lstquestion}[<options>]
<listing>
\end{lstquestion}

允许<options>设置在列表之前或之后包含的文本并指定问题的点数。

\documentclass{article}

\usepackage{exsheets}
\usepackage{exsheets-listings}

\lstdefinestyle{exercise}{
  frame=single,
  xleftmargin=20pt,
  numbers=left,
  numberstyle=\small,
  tabsize=2,
  breaklines,
  showspaces=false,
  showstringspaces=false,
  language=C,
  basicstyle=\small\ttfamily,
  commentstyle=\itshape\color{gray}
}
\SetupExSheets{
  question/listings={style=exercise} ,
  solution/listings={style=exercise}
}

\begin{document}

\begin{lstquestion}[
  pre    = {Pre-example text} ,
  post   = {Post-example text} ,
  points = 6]
#include <stdio.h>

int main(int argc, char *argv[]) {
  printf("hello, world\n");
}
\end{lstquestion}


\begin{lstsolution}[
  pre  = {Pre-solution-text} ,
  post = {Post-solution text}]
#include <stdio.h>

int main(int argc, char *argv[]) {
  printf("hello, world\n");
  # some more things that had to be done
}
\end{lstsolution}

\printsolutions 

\end{document}

在此处输入图片描述


初步答案

这是一条建议。代码可以改进(我现在时间有点紧……如果我有时间,我可能会用它作为扩展的基础exsheets)。

下面我提供了一个包的代码exsheets-listings。它定义了两个环境:

\begin{lstquestion}[<options>]{<pre>}{<post>}{<points>}
<listing>
\end{lstquestion}

\begin{lstsolution}[<options>]{<pre>}{<post>}
<listing>
\end{lstsolution}

他们将列表写入辅助文件,每个问题和每个解决方案一个,然后通过 进行内部输入\lstinputlisting。这个 MWE

\documentclass{article}

\usepackage{exsheets}
\usepackage{exsheets-listings}

\begin{document}

\begin{lstquestion}{Pre-example text}{Post-example text}{6}
#include <stdio.h>

int main(int argc, char *argv[]) {
  printf("hello, world\n");
}
\end{lstquestion}


\begin{lstsolution}{Pre-solution-text}{Post-solution text}
#include <stdio.h>

int main(int argc, char *argv[]) {
  printf("hello, world\n");
  # some more things that had to be done
}
\end{lstsolution}

\printsolutions 

\end{document}

将以下代码保存到exsheets-listings.styTeX 可以找到的地方(首先保存在您的工作文件夹中):

\ProvidesPackage{exsheets-listings.sty}[2013/09/18 v0.1 listings in exsheets]
\RequirePackage{listings,xcolor,exsheets}

\lstdefinestyle{exercise}{
  frame=single,
  xleftmargin=20pt,
  numbers=left,
  numberstyle=\small,
  tabsize=2,
  breaklines,
  showspaces=false,
  showstringspaces=false,
  language=C,
  basicstyle=\small\ttfamily,
  commentstyle=\itshape\color{gray}
}

\ExplSyntaxOn
\cs_new:Npn \lst_question_expandopt:Nnnnn #1#2#3#4#5
  { #1{#2}[#3]{#4}#5 }
\cs_generate_variant:Nn \lst_question_expandopt:Nnnnn { NnVnx }
\cs_new_eq:NN \lst@question@expandoption \lst_question_expandopt:NnVnx

\cs_new:Npn \lst_question_expand_opt_and_body:Nnnn #1#2#3#4
  { #1{#2}[#3]#4 }
\cs_generate_variant:Nn \lst_question_expand_opt_and_body:Nnnn { NnVx }
\cs_new_eq:NN
  \lst@question@expand@option@and@body
  \lst_question_expand_opt_and_body:NnVx
\ExplSyntaxOff

\lst@RequireAspects{writefile}

\newsavebox\lst@question@box

\newcounter{questionlisting}

\lstnewenvironment{lstquestion}[4][]{%
  \def\lst@question@pre{#2}%
  \def\lst@question@post{#3}%
  \def\lst@question@points{#4}%
  \def\lst@question@options{#1}%
  \stepcounter{questionlisting}%
  \setbox\lst@question@box=\hbox\bgroup
    \lst@BeginAlsoWriteFile{\jobname-ex\thequestionlisting.lst}
}
{%
    \lst@EndWriteFile
  \egroup
  \lst@question@expandoption
  \begin{question}\lst@question@options{\lst@question@points}{%
    \lst@question@pre
    \noexpand\lstinputlisting[style=exercise]
      {\jobname-ex\thequestionlisting.lst}%
    \lst@question@post
  }%
  \end{question}%
}

\newcounter{solutionlisting}

\lstnewenvironment{lstsolution}[3][]{%
  \def\lst@question@pre{#2}%
  \def\lst@question@post{#3}%
  \def\lst@question@options{#1}%
  \stepcounter{solutionlisting}%
  \setbox\lst@question@box=\vbox\bgroup
    \lst@BeginAlsoWriteFile{\jobname-sol\thesolutionlisting.lst}
}
{%
    \lst@EndWriteFile
  \egroup
  \lst@question@expand@option@and@body
  \begin{solution}\lst@question@options{%
    \expandonce\lst@question@pre
    \noexpand\lstinputlisting[style=exercise]
      {\jobname-sol\thesolutionlisting.lst}%
    \expandonce\lst@question@post
  }%
  \end{solution}%
}
\endinput

答案2

如果我在 ConTeXt 中执行类似操作,我会使用缓冲区来存储逐字文本,并使用键值驱动接口来指定前置和后置参数。即使您不使用 ConTeXt,以下代码的要点也应该是可以理解的。

\definenamespace
  [exercisesolution]
  [
    name=exercisesolution,
    setup=yes,
  ]

\defineenumeration[exercise][text=Exericse] 
\defineenumeration[solution][text=Solution]

\define\useexercisesolution
    {\dosingleargument\dodefineexercisesolution}

\def\dodefineexercisesolution[#1]%
    {\setupexercisesolution[#1]%
     \startexercise
       \exercisesolutionparameter{exercisebefore}%
       \typebuffer[\exercisesolutionparameter{bufferbefore},
                   \exercisesolutionparameter{bufferexercise},
                   \exercisesolutionparameter{bufferafter}]%
      \exercisesolutionparameter{exerciseafter}%
    \stopexercise
    \startsolution
       \exercisesolutionparameter{solutionbefore}%
       \typebuffer[\exercisesolutionparameter{bufferbefore},
                   \exercisesolutionparameter{bufferexercise},
                   \exercisesolutionparameter{buffersolution},
                   \exercisesolutionparameter{bufferafter}]%
      \exercisesolutionparameter{solutionafter}%
    \stopsolution}


\startbuffer[C-header]
#include <stdio.h>

int main(int argc, char *argv[]) {
\stopbuffer

\startbuffer[C-footer]
}
\stopbuffer

% Common setup for all questions
\setupexercisesolution
  [bufferbefore=C-header,
   bufferafter=C-footer]

\starttext

\startbuffer[question]
    printf("Hello World\n");
\stopbuffer

\startbuffer[answer]
    # Some more things that need to be done
    # and then more, as this is the solution
\stopbuffer

\useexercisesolution
  [
    exercisebefore={Pre example text},
    exerciseafter={Post example text},
    solutionbefore={Pre solution text},
    solutionafter={Post solution text},
    bufferexercise=question,
    buffersolution=answer,
  ]

\stoptext

这使

在此处输入图片描述

请注意,我也重复使用样板代码,并假设练习中提供的代码将始终在解决方案中重复。

可以添加语法高亮(vim 模块)和框架,但我省略了它们,以便更容易看到内容是如何被重复使用的。

相关内容