ID de requisitos únicos y lista de métodos de prueba correspondientes

ID de requisitos únicos y lista de métodos de prueba correspondientes

Aprendí a crear requisitos con ID únicos.en esta publicación. Ahora me gustaría agregar un método de prueba para cada requisito; en el código estoy pensando en algo como esto:

\Requirement{SOMEID}{This is the requirement text.}{This describes the testmethod.}

Más adelante, en una sección diferente, quiero iterar sobre estos métodos de prueba para enumerarlos. Al final estoy buscando algo como esto:

ingrese la descripción de la imagen aquí

La primera parte me queda clara, pero ¿cómo se puede "almacenar" un parámetro (los métodos de prueba) para usarlo más adelante?

Respuesta1

Necesita algo de “memoria asociativa”, que se puede implementar con \csnameestructuras de datos ya proporcionadas por expl3.

Aquí \Requirementse almacena el ID en una secuencia para indexarlo y luego ambos textos en una lista de propiedades. Aquí no se utiliza realmente el almacenamiento del texto de requisitos, pero puede decidir usarlo de una manera diferente, por lo que es mejor almacenarlo también.

Cuando sea necesario, la secuencia se puede mapear para entregar todos los métodos de prueba almacenados en el momento de la definición.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\Requirement}{mmm}
 {
  \subsubsection*{Requirement ~ ID ~ #1}
  #2
  \jfb_requirement_store:nnn { #1 } { #2 } { #3 }
 }
\NewDocumentCommand{\DescribeRequirements}{}
 {
  \seq_map_inline:Nn \g_jfb_requirement_ids_seq
   {
    \subsubsection*{##1} \prop_item:Nn \g_jfb_requirement_ids_prop { ##1@B } \par
   }
 }

\seq_new:N \g_jfb_requirement_ids_seq
\prop_new:N \g_jfb_requirement_ids_prop

\cs_new_protected:Nn \jfb_requirement_store:nnn
 {
  \seq_gput_right:Nn \g_jfb_requirement_ids_seq { #1 }
  \prop_gput:Nnx \g_jfb_requirement_ids_prop { #1@A } { \tl_trim_spaces:n { #2 } }
  \prop_gput:Nnx \g_jfb_requirement_ids_prop { #1@B } { \tl_trim_spaces:n { #3 } }
 }

\ExplSyntaxOff

\begin{document}

\section{Introduction}

Blah.

\section{Requirements}

\Requirement{SOMEID}{This is the requirement text.}{This describes the test method.}

\Requirement{SOMEOTHERID}{
  This is the other requirement text.
}{
  This describes the other test method.
}

\section{Test Methods}

\DescribeRequirements

\end{document}

ingrese la descripción de la imagen aquí

Respuesta2

Podrías usar el mecanismo \@starttoc- - de LaTeX \addtocontentspara esto.

Intenté asegurarme de que el siguiente ejemplo se compilara con y sinhiperrrefsiendo cargado.

También traté de asegurarme de que \labellas \refreferencias y los marcadores funcionen.

Es posible que necesite compilar el ejemplo varias veces sin eliminar archivos auxiliares entre ejecuciones de LaTeX para que todo coincida correctamente.

\documentclass{article}

\usepackage{hyperref}

\newcounter{TestMethod}
\newcounter{Requirement}

\makeatletter
\newcommand\listofrequirements{%
  \section{Requirements}%
  \IfFileExists{\jobname.lfr}{}{\par\noindent No requirements available.}%
  \@starttoc{lfr}%
}%
\newcommand\listoftestmethods{%
  \section{Testmethods}%
  \begin{description}%
  \def\makelabel##1{\hspace\labelsep\normalfont\bfseries##1}%
  \IfFileExists{\jobname.ltm}{}{\item[\textnormal{No test-methods available.}]\relax}%
  \@starttoc{ltm}%
  \end{description}%
}%
\newcommand\@multipleRequirements{}%
\AtEndDocument{\@multipleRequirements}%
\begingroup
\catcode`\/=14 %
\catcode`\%=12 /
\@firstofone{/
\endgroup
\newcommand\Requirement[3]{/
  \@bsphack
  {/
    \@ifundefined{Requirement@#1}{\global\@namedef{Requirement@#1}{DEFINED}}{/
      \gdef\@multipleRequirements{\@latex@warning@no@line{There were multiply-defined requirements}}/
      \@latex@warning{Requirement `#1' multiply defined}/
    }/
  }/
  \begingroup
  // Let's have \addtocontents / \protected@write write immediately:
  \let\writecopy\write
  \def\write{\immediate\writecopy}/
  // Prevent all of \protected@write's expansion (\edef-with \protect-mechanism-expansion and \write-expansion)
  // by nesting things either into two token-registers or into two \unexpanded.
  \toks@{\the\@temptokena}/
  \@temptokena\expandafter{\string\l@Requirement{%^^J{#1}%^^J{#2}%^^J}}/
  \addtocontents{lfr}{\the\toks@\relax}/
  \@temptokena\expandafter{\string\l@TestMethod{%^^J{#1}%^^J{#3}%^^J}}/
  \addtocontents{ltm}{\the\toks@\relax}/
  /\addtocontents{lfr}{\unexpanded{\unexpanded\expandafter{\string\l@Requirement{%^^J{#1}%^^J{#2}%^^J}}}\relax}/
  /\addtocontents{ltm}{\unexpanded{\unexpanded\expandafter{\string\l@TestMethod{%^^J{#1}%^^J{#3}%^^J}}}\relax}/
  \endgroup
  \@esphack
}/
}%
\newcommand\l@Requirement[1]{%
  %#1 =  {ID}{<requirement-text>}
  \PrintRequirement#1%
}%
\newcommand\l@TestMethod[1]{%
  %#1 = {ID}{<requirement-text>}
  \PrintTestMethod#1%
}%
\newcommand\PrintRequirement[2]{%
  %#1 = ID; #2 = <requirement-text>;
  \ifhmode\medskip\fi\par\noindent
  \begingroup
  \def\theRequirement{#1}%
  \refstepcounter{Requirement}%
  \def\@currentlabelname{#1}%
  \label{RequirementNamespace@Requirement #1}%
  \@ifundefined{Hy@raisedlink}{}{%
    \@tempcnta\Hy@currentbookmarklevel
    \Hy@StepCount\@tempcnta
    \expandafter\RequirementPassFirstToSecond\expandafter{\the\@tempcnta}%
    {\Hy@writebookmark{}{#1}{\@currentHref}}{toc}%
    \advance \@tempcnta by -1 %
    \xdef\Hy@currentbookmarklevel{\the \@tempcnta}%
    \@ifundefined{r@RequirementNamespace@TestMethod #1}{}{%
      \hyperref[{RequirementNamespace@TestMethod #1}]%
    }%
  }%
  {\textbf{Requirement~ID~{#1}}}%
  \\{#2}%
  \endgroup
}%
\newcommand\Requirement@MoveLabelData{}%
\newcommand\RequirementPassFirstToSecond[2]{#2{#1}}%
\newcommand\PrintTestMethod[2]{%
  %#1 = ID; #2 = <requirement-text>;
  \item[{%
    \def\theTestMethod{#1}%
    \refstepcounter{TestMethod}%
    \def\@currentlabelname{#1}%
    \expandafter\gdef\expandafter\Requirement@MoveLabelData\expandafter{%
      \romannumeral0%
      \expandafter\RequirementPassFirstToSecond\expandafter{\@currentlabel}{%
        \@ifundefined{Hy@raisedlink}{ }{%
          \expandafter\RequirementPassFirstToSecond\expandafter{\@currentlabelname}{%
            \expandafter\RequirementPassFirstToSecond\expandafter{\@currentHref}{ %<- This space must be!
              \def\@currentHref
            }%
            \def\@currentlabelname
          }%
        }%
        \def\@currentlabel
      }%
    }%
    \label{RequirementNamespace@TestMethod #1}%
    \@ifundefined{Hy@raisedlink}{}{%
      \@tempcnta\Hy@currentbookmarklevel
      \Hy@StepCount\@tempcnta
      \expandafter\RequirementPassFirstToSecond\expandafter{\the\@tempcnta}%
      {\Hy@writebookmark{}{#1}{\@currentHref}}{toc}%
      \advance\@tempcnta by -1 %
      \xdef\Hy@currentbookmarklevel{\the \@tempcnta}%
      \@ifundefined{r@RequirementNamespace@Requirement #1}{}{%
        \hyperref[{RequirementNamespace@Requirement #1}]%
      }%
    }%
    {#1:}%
  }]%
  \Requirement@MoveLabelData
  #2%
}%
\makeatother

\begin{document}

\section{This is just some section}

This is text in the section.

\noindent Reference to the requirement with ID ``SOMEOTHERID'': \ref{AA}.

\noindent Reference to the testing-method with ID ``SOMEOTHERID'': \ref{BB}.

\Requirement{SOMEID}{This is the requirement text.}{This describes the testmethod.}
\Requirement{SOMEOTHERID}{This \label{AA} is some different requirement text.}{This \label{BB} describes some different testmethod.}

\listofrequirements

\listoftestmethods

\end{document}

En caso de que tenga líneas demasiado largas en los archivos auxiliares, puede hacer que algunos de los argumentos se lean y escriban en régimen de código de categoría palabra por palabra. Si hace eso, la macro \Requirementno podrá usarse dentro de las definiciones y/o argumentos de otras macros.

Al principio no pude hacerlo funcionar.xparseEs v+de tipo argumento, así que usé lo mío.

No pude hacerlo funcionarxparse's v+-tipo-argumento por el siguiente motivo:xparseEl v+tipo de argumento utiliza el ^^Mcarácter = el carácter ⟨retorno⟩ para indicar los extremos de las líneas. ( ^^M= ^^-notación para el carácter cuyo punto de código es 13 en el esquema de codificación de caracteres interno del motor TeX: M es la decimotercera letra del alfabeto; el punto de código 13 del esquema de codificación de caracteres interno del motor TeX a su vez denota el ⟨return⟩-character.) Entonces, al momento de escribir el v+argumento -para el archivo, el parámetro entero \newlinechartambién debe indicar ese carácter. Por lo tanto, será mejor que no use \protected@writepara escribir el v+argumento -en el archivo, sino algo que lo haga \writeinmediatamente, mientras que el cambio de\newlinechar de todavía esté vigente. En mis primeros intentos conxparse's v+-argument-type Pasé por alto que el \writedebe tener lugar de inmediato.

Aquí viene lo mío, pero detrás de eso agregué otro ejemplo, usandoxparsey su v+tipo -argument para recuperar los argumentos textuales:

\documentclass{article}

\usepackage{hyperref}

\newcounter{TestMethod}
\newcounter{Requirement}

\makeatletter

%%======================Code for \UDcollectverbarg=============================
%% \UDcollectverbarg{^^M-replacement}{<mandatory 1>}{<mandatory 2>}|<verbatim arg>|
%% 
%% reads <verbatim arg> under verbatim-catcode-regime and delivers:
%%
%%    <mandatory 1>{<mandatory 2>{<verbatim arg>}{|<verbatim arg>|}}
%%
%% Instead of verbatim-delimiter | the <verbatim arg> can be nested in braces.
%% You cannot use percent or spaces or horizontal tab as verbatim-delimiter.
%%
%% You can use <mandatory 1> for nesting calls to \UDcollectverbarg.
%% <mandatory 2> gets the <verbatim arg> twice: Once without verbatim-delimiters/braces,
%% once surrounded by verbatim-delimiters/braces.
%% Reason: When you feed it to \scantokens you don't need the verbatim-delimiters.
%%         When you use it for writing to temporary files and reading back,
%%         you need them.
%%=============================================================================
%% Check whether argument is empty:
%%=============================================================================
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is empty>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is not empty>}%
%%    
%% Due to \romannumeral0-expansion the result is delivered after two
%% expansion-steps/after two "hits" by \expandafter.
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
%%
\long\def\UD@CheckWhetherNull#1{%
  \romannumeral0\expandafter\@secondoftwo\string{\expandafter
  \@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
  \@secondoftwo\string}\@firstoftwo\expandafter{} \@secondoftwo}%
  {\@firstoftwo\expandafter{} \@firstoftwo}%
}%
%%=============================================================================
\begingroup
\@makeother\^^M%
\@firstofone{%
  \endgroup%
  \newcommand\UDEndlreplace[2]{\romannumeral0\@UDEndlreplace{#2}#1^^M\relax{}}%
  \@ifdefinable\@UDEndlreplace{%
    \long\def\@UDEndlreplace#1#2^^M#3\relax#4#5{%
      \UD@CheckWhetherNull{#3}%
      { #5{#4#2}}{\@UDEndlreplace{#1}#3\relax{#4#2#1}{#5}}%
    }%
  }%
}%
\newcommand\UDcollectverbarg[3]{%
  \begingroup
  \let\do\@makeother % <- this and the next line switch to
  \dospecials        %    verbatim-category-code-régime.
  \catcode`\{=1      % <- give opening curly brace the usual catcode so a 
                     %    curly-brace-balanced argument can be gathered in
                     %    case of the first thing of the verbatimized-argument 
                     %    being a curly opening brace.
  \catcode`\ =10     % <- give space and horizontal tab the usual catcode so \UD@collectverbarg
  \catcode`\^^I=10   %    cannot catch a space or a horizontal tab as its 4th undelimited argument.
                     %    (Its 4th undelimited argument denotes the verbatim-
                     %     syntax-delimiter in case of not gathering a
                     %     curly-brace-nested argument.)
  \catcode`\%=14     % <- make percent comment.
  \kernel@ifnextchar\bgroup
  {% seems a curly-brace-nested argument is to be caught:
    \catcode`\}=2    % <- give closing curly brace the usual catcode also.
    \UD@collectverbarg{#1}{#2}{#3}{}%
  }{% seems an argument with verbatim-syntax-delimiter is to be caught:
    \do\{% <- give opening curly brace the verbatim-catcode again.
    \UD@collectverbarg{#1}{#2}{#3}%
  }%
}%
\newcommand\UD@collectverbarg[4]{%
  \do\ %   <- Now that \UD@collectverbarg has the delimiter or
  \do\^^I%    emptiness in its 4th arg, give space and horizontal tab
         %    the verbatim-catcode again.
  \do\^^M% <- Give the carriage-return-character the verbatim-catcode.
  \do\%%   <- Give the percent-character the verbatim-catcode.
  \long\def\@tempb##1#4{%
    \def\@tempb{##1}%
    \UD@CheckWhetherNull{#4}{%
      \def\@tempc{{##1}}%
    }{%
      \def\@tempc{#4##1#4}%
    }%
    \@onelevel@sanitize\@tempb % <- Turn characters into their "12/other"-pendants.
                               %    This may be important with things like the 
                               %    inputenc-package which may make characters 
                               %    active/which give them catcode 13(active).
    \expandafter\UDEndlreplace\expandafter{\@tempb}{#1}{\def\@tempb}% <- this starts 
                               %    the loop for replacing endline-characters.
    \@onelevel@sanitize\@tempc
    \expandafter\UDEndlreplace\expandafter{\@tempc}{#1}{\def\@tempc}%
    \expandafter\expandafter\expandafter\UD@@collectverbarg% <- this "spits out the result.
    \expandafter\expandafter\expandafter{%
    \expandafter\@tempb\expandafter}%
    \expandafter{\@tempc}{#2}{#3}%
  }%
  \@tempb
}%
\newcommand\UD@@collectverbarg[4]{%
  \endgroup
  #3{#4{#1}{#2}}%
}%
%%================= End of code for \UDcollectverbarg =========================

\newcommand\listofrequirements{%
  \section{Requirements}%
  \IfFileExists{\jobname.lfr}{}{\par\noindent No requirements available.}%
  \@starttoc{lfr}%
}%
\newcommand\listoftestmethods{%
  \section{Testmethods}%
  \begin{description}%
  \def\makelabel##1{\hspace\labelsep\normalfont\bfseries##1}%
  \IfFileExists{\jobname.ltm}{}{\item[\textnormal{No test-methods available.}]\relax}%
  \@starttoc{ltm}%
  \end{description}%
}%
\newcommand\@multipleRequirements{}%
\AtEndDocument{\@multipleRequirements}%
\newcommand\Requirement[1]{%
   \@bsphack
   \UDcollectverbarg{^^J}{%
     \UDcollectverbarg{^^J}{\@firstofone}%
   }{\InnerRequirement{#1}}%
}%
\newcommand\InnerRequirement[5]{%
  {%
    \@ifundefined{Requirement@#1}{\global\@namedef{Requirement@#1}{DEFINED}}{%
      \gdef\@multipleRequirements{\@latex@warning@no@line{There were multiply-defined requirements}}%
      \@latex@warning{Requirement `#1' multiply defined}%
    }%
  }%
  \begingroup
  \immediate\write\@auxout{\string\Requirementwritefile{lfr}{Requirement}{#1}#3}%
  \immediate\write\@auxout{\string\Requirementwritefile{ltm}{TestMethod}{#1}#5}%
  \endgroup
  \@esphack
}%
\newcommand\Requirementwritefile[3]{%
  \UDcollectverbarg{^^J}{\@firstofone}{%
    \expandafter\expandafter\expandafter\RequirementPassFirstToSecond
    \expandafter\expandafter\expandafter{\expandafter\string\csname l@#2\endcsname}%
    {\RequirementwritefileInner{#1}}{#3}%
  }%
}%
\begingroup
\catcode`\/=14 %
\@makeother{\%}/
\@firstofone{/
  \endgroup
  \newcommand\RequirementwritefileInner[5]{/
    \@writefile{#1}{/
      #2{%^^J/
      {#3}%^^J/
      {#4}%^^J/
      }%/
    }/
  }/
}%
\newcommand\l@Requirement[1]{%
  %#1 =  {ID}{<requirement-text>}
  \PrintRequirement#1%
}%
\newcommand\l@TestMethod[1]{%
  %#1 = {ID}{<requirement-text>}
  \PrintTestMethod#1%
}%
\newcommand\PrintRequirement[2]{%
  %#1 = ID; #2 = <requirement-text>;
  \ifhmode\medskip\fi\par\noindent
  \begingroup
  \def\theRequirement{#1}%
  \refstepcounter{Requirement}%
  \def\@currentlabelname{#1}%
  \label{RequirementNamespace@Requirement #1}%
  \@ifundefined{Hy@raisedlink}{}{%
    \@tempcnta\Hy@currentbookmarklevel
    \Hy@StepCount\@tempcnta
    \expandafter\RequirementPassFirstToSecond\expandafter{\the\@tempcnta}%
    {\Hy@writebookmark{}{#1}{\@currentHref}}{toc}%
    \advance\@tempcnta by -1 %
    \xdef\Hy@currentbookmarklevel{\the\@tempcnta}%
    \@ifundefined{r@RequirementNamespace@TestMethod #1}{}{%
      \hyperref[{RequirementNamespace@TestMethod #1}]%
    }%
  }%
  {\textbf{Requirement~ID~{#1}}}%
  \\{#2}%
  \endgroup
}%
\newcommand\Requirement@MoveLabelData{}%
\newcommand\RequirementPassFirstToSecond[2]{#2{#1}}%
\newcommand\PrintTestMethod[2]{%
  %#1 = ID; #2 = <requirement-text>;
  \item[{%
    \def\theTestMethod{#1}%
    \refstepcounter{TestMethod}%
    \def\@currentlabelname{#1}%
    \expandafter\gdef\expandafter\Requirement@MoveLabelData\expandafter{%
      \romannumeral0%
      \expandafter\RequirementPassFirstToSecond\expandafter{\@currentlabel}{%
        \@ifundefined{Hy@raisedlink}{ }{%
          \expandafter\RequirementPassFirstToSecond\expandafter{\@currentlabelname}{%
            \expandafter\RequirementPassFirstToSecond\expandafter{\@currentHref}{ %<- This space must be!
              \def\@currentHref
            }%
            \def\@currentlabelname
          }%
        }%
        \def\@currentlabel
      }%
    }%
    \label{RequirementNamespace@TestMethod #1}%
    \@ifundefined{Hy@raisedlink}{}{%
      \@tempcnta\Hy@currentbookmarklevel
      \Hy@StepCount\@tempcnta
      \expandafter\RequirementPassFirstToSecond\expandafter{\the\@tempcnta}%
      {\Hy@writebookmark{}{#1}{\@currentHref}}{toc}%
      \advance\@tempcnta by -1 %
      \xdef\Hy@currentbookmarklevel{\the\@tempcnta}%
      \@ifundefined{r@RequirementNamespace@Requirement #1}{}{%
        \hyperref[{RequirementNamespace@Requirement #1}]%
      }%
    }%
    {#1:}%
  }]%
  \Requirement@MoveLabelData
  #2%
}%
\makeatother

\begin{document}

\section{This is just some section}

This is text in the section.

\noindent Reference to the requirement with ID ``SOMEOTHERID'': \ref{AA}.

\noindent Reference to the testing-method with ID ``SOMEOTHERID'': \ref{BB}.

\Requirement{SOMEID}{This is the requirement text.}{This describes the testmethod.}
\Requirement{SOMEOTHERID}{This \label{AA} is some different requirement text.}{This \label{BB} describes some different testmethod.}

\listofrequirements

\listoftestmethods

\end{document}

Aquí está el ejemplo con el argumento textual, usandoxparse's +v-tipo-argumento:

\documentclass{article}

\usepackage{xparse}
\usepackage{hyperref}

\newcounter{TestMethod}
\newcounter{Requirement}

\makeatletter
\NewDocumentCommand{\listofrequirements}{}{%
  \section{Requirements}%
  \IfFileExists{\jobname.lfr}{}{\par\noindent No requirements available.}%
  \@starttoc{lfr}%
}%
\NewDocumentCommand{\listoftestmethods}{}{%
  \section{Testmethods}%
  \begin{description}%
  \def\makelabel##1{\hspace\labelsep\normalfont\bfseries##1}%
  \IfFileExists{\jobname.ltm}{}{\item[\textnormal{No test-methods available.}]\relax}%
  \@starttoc{ltm}%
  \end{description}%
}%
\NewDocumentCommand{\@multipleRequirements}{}{}%
\AtEndDocument{\@multipleRequirements}%
\NewDocumentCommand{\Requirement}{m}{%
   \begingroup
   \@makeother{\^^I}%
   \InnerRequirement{#1}%
}%
\begingroup
\catcode`\/=14 %
\@makeother{\%}/
\@makeother{\^^M}/
\@firstofone{/
\endgroup/
\NewDocumentCommand{\InnerRequirement}{m+v+v}{/
  \endgroup/
  {/
    \@ifundefined{Requirement@#1}{\global\@namedef{Requirement@#1}{DEFINED}}{/
      \gdef\@multipleRequirements{\@latex@warning@no@line{There were multiply-defined requirements}}/
      \@latex@warning{Requirement `#1' multiply defined}/
    }/
  }/
  \begingroup/
  \newlinechar=\endlinechar/
  \immediate\write\@auxout{/
    \string\Requirementwritefile{lfr}/
                                {\unexpanded\expandafter{\string\l@Requirement{%^^M{#1}%^^M{#2}%^^M}}%}/
  }/
  \immediate\write\@auxout{/
    \string\Requirementwritefile{ltm}/
                                {\unexpanded\expandafter{\string\l@TestMethod{%^^M{#1}%^^M{#3}%^^M}}%}/
  }/
  \endgroup/
  \@esphack/
}/
}%
\NewDocumentCommand{\Requirementwritefile}{m}{%
  \begingroup
  \@makeother{\^^I}%
  \RequirementwritefileInner{#1}%
}%
\NewDocumentCommand{\RequirementwritefileInner}{m+v}{%
  \newlinechar=\endlinechar
  \@writefile{#1}{#2}%
  \endgroup
}%
\NewDocumentCommand{\l@Requirement}{+m}{%
  %#1 =  {ID}{<requirement-text>}
  \PrintRequirement#1%
}%
\NewDocumentCommand{\l@TestMethod}{+m}{%
  %#1 = {ID}{<requirement-text>}
  \PrintTestMethod#1%
}%
\NewDocumentCommand{\PrintRequirement}{+m+m}{%
  %#1 = ID; #2 = <requirement-text>;
  \ifhmode\medskip\fi\par\noindent
  \begingroup
  \def\theRequirement{#1}%
  \refstepcounter{Requirement}%
  \def\@currentlabelname{#1}%
  \label{RequirementNamespace@Requirement #1}%
  \@ifundefined{Hy@raisedlink}{}{%
    \@tempcnta\Hy@currentbookmarklevel
    \Hy@StepCount\@tempcnta
    \expandafter\RequirementPassFirstToSecond\expandafter{\the\@tempcnta}%
    {\Hy@writebookmark{}{#1}{\@currentHref}}{toc}%
    \advance\@tempcnta by -1 %
    \xdef\Hy@currentbookmarklevel{\the \@tempcnta}%
    \@ifundefined{r@RequirementNamespace@TestMethod #1}{}{%
      \hyperref[{RequirementNamespace@TestMethod #1}]%
    }%
  }%
  {\textbf{Requirement~ID~{#1}}}%
  \\{#2}%
  \endgroup
}%
\NewDocumentCommand{\Requirement@MoveLabelData}{}{}%
\NewDocumentCommand{\RequirementPassFirstToSecond}{+m+m}{#2{#1}}%
\NewDocumentCommand{\PrintTestMethod}{+m+m}{%
  %#1 = ID; #2 = <requirement-text>;
  \item[{%
    \def\theTestMethod{#1}%
    \refstepcounter{TestMethod}%
    \def\@currentlabelname{#1}%
    \expandafter\gdef\expandafter\Requirement@MoveLabelData\expandafter{%
      \romannumeral0%
      \expandafter\RequirementPassFirstToSecond\expandafter{\@currentlabel}{%
        \@ifundefined{Hy@raisedlink}{ }{%
          \expandafter\RequirementPassFirstToSecond\expandafter{\@currentlabelname}{%
            \expandafter\RequirementPassFirstToSecond\expandafter{\@currentHref}{ %<- This space must be!
              \def\@currentHref
            }%
            \def\@currentlabelname
          }%
        }%
        \def\@currentlabel
      }%
    }%
    \label{RequirementNamespace@TestMethod #1}%
    \@ifundefined{Hy@raisedlink}{}{%
      \@tempcnta\Hy@currentbookmarklevel
      \Hy@StepCount\@tempcnta
      \expandafter\RequirementPassFirstToSecond\expandafter{\the\@tempcnta}%
      {\Hy@writebookmark{}{#1}{\@currentHref}}{toc}%
      \advance \@tempcnta by -1 %
      \xdef\Hy@currentbookmarklevel{\the \@tempcnta}%
      \@ifundefined{r@RequirementNamespace@Requirement #1}{}{%
        \hyperref[{RequirementNamespace@Requirement #1}]%
      }%
    }%
    {#1:}%
  }]%
  \Requirement@MoveLabelData
  #2%
}%
\makeatother

\begin{document}

\section{This is just some section}

This is text in the section.

\noindent Reference to the requirement with ID ``SOMEOTHERID'': \ref{AA}.

\noindent Reference to the testing-method with ID ``SOMEOTHERID'': \ref{BB}.

\Requirement{SOMEID}{This is the requirement text.}{This describes the testmethod.}
\Requirement{SOMEOTHERID}{This \label{AA} is some different requirement text.}{This \label{BB} describes some different testmethod.}

\listofrequirements

\listoftestmethods

\end{document}

ingrese la descripción de la imagen aquí

información relacionada