
Aprendi como criar requisitos com IDs exclusivosnesta postagem. Agora eu gostaria de adicionar um método de teste para cada requisito - no código estou pensando em algo assim:
\Requirement{SOMEID}{This is the requirement text.}{This describes the testmethod.}
Posteriormente, em uma seção diferente, quero iterar sobre esses métodos de teste para listá-los. No final estou procurando algo assim:
A primeira parte está clara para mim, mas como você pode "armazenar" um parâmetro (os testmethods) para usá-lo posteriormente?
Responder1
Você precisa de alguma “memória associativa”, que pode ser implementada com \csname
ou com estruturas de dados já fornecidas pelo expl3
.
Aqui \Requirement
armazena o ID em uma sequência para indexá-lo, depois ambos os textos em uma lista de propriedades. Armazenar o texto do requisito não é realmente usado aqui, mas você pode decidir usá-lo de uma maneira diferente, então é melhor armazená-lo também.
Quando necessário, a sequência pode ser mapeada para entregar todos os métodos de teste armazenados no momento da definição.
\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}
Responder2
Você poderia usar o mecanismo \@starttoc
- do LaTeX \addtocontents
para isso.
Tentei ter certeza de que o exemplo a seguir compila com e semhiperrefsendo carregado.
Também tentei ter certeza de que \label
- \ref
-referências e marcadores funcionassem.
Você pode precisar compilar o exemplo várias vezes sem excluir arquivos auxiliares entre as execuções do LaTeX para que tudo corresponda corretamente.
\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}
Caso você coloque linhas muito longas nos arquivos auxiliares, você pode ter alguns dos argumentos lidos e escritos em regime de código de categoria literal. Se você fizer isso, a macro \Requirement
não poderá ser usada dentro das definições e/ou argumentos de outras macros.
No começo eu não consegui fazê-lo funcionarxparseé v+
-argument-type, então usei minhas próprias coisas.
Não consegui fazê-lo funcionarxparse's v+
-argument-type pelo seguinte motivo:xparseO v+
-argument-type de usa o ^^M
-character = o caractere ⟨return⟩ para denotar fins de linhas. ( ^^M
= ^^
-notação para o caractere cujo ponto de código é 13 no esquema de codificação de caracteres interno do mecanismo TeX - M é a 13ª letra do alfabeto; o ponto de código 13 do esquema de codificação de caracteres interno do mecanismo TeX, por sua vez, denota o ⟨return⟩-character.) Portanto, no momento de escrever o v+
argumento -no arquivo, o parâmetro inteiro \newlinechar
também deve denotar esse caractere. Portanto, é melhor não usar \protected@write
para escrever o v+
argumento - no arquivo, mas algo que faça isso \write
imediatamente, enquanto a alteração de \newlinechar
ainda estiver em vigor. Nas minhas primeiras tentativas comxparse's v+
-argument-type eu esqueci que o \write
deve ocorrer imediatamente.
Aí vem minha própria coisa, mas atrás disso adicionei outro exemplo, usandoxparsee seu v+
-argument-type para buscar os argumentos literalizados:
\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}
Aqui está o exemplo com o argumento verbalizado, usandoxparse's +v
-argument-type:
\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}