2

I am writing a system requirement specification document (SRS) that contains requirements as block of text with a custom formatting. I made a latex environment to format such block, here the code:

\documentclass{article}
\usepackage[most]{tcolorblox}

%param1 project name (was used to name the counter but because usually it is a macro 
%                     in the invoaction it breakes the \newcounter command)
%param2 function
\newcommand{\makereqtype}[2]{ \newcounter{#2-cnt} }
%param1: project name
%param2: function
\NewDocumentEnvironment{requirement}{mm}
{
    \begin{tcolorbox}[boxrule=0pt,frame hidden,sharp corners,enhanced,borderline west={1pt}{0pt}{black}]
    \texttt{#1.\uppercase{#2}.\arabic{#2-cnt}}\\
    }{\stepcounter{#2-cnt}
    \end{tcolorbox}%
}

%That is invoked in the text like this:
\begin{document}
\makereqtype{PROJECT\_NAME}{FUNCTION1} %% do this only once

%% For each requirement of functionality FUNCTION1 do:
\begin{requirement}{PROJECT\_NAME}{FUNCTION1}
requirement stuff
\end{requirement}
\begin{requirement}{PROJECT\_NAME}{FUNCTION1}
requirement stuff
\end{requirement}
\end{document}

The output is as follows: enter image description here The basic idea is to format the text as in the image with an auto-incrementing number for each time the environment is used in the text. I have two problems with this approach that I don't know how to solve:

  1. The two custom commands that I made are really delicate, they could brake during invocation if the parameters are not text but latex functions (e.g. \uppercase{projectname}, or expansion of an acronym from acronyms package \ac{prj}) or something else (say instead of FUNCTION1 i use FUNCTION\_NAME
  2. The biggest problem is that I want to reference the requirements as you do with latex chapters by using a label. But when you reference the label I want the full name of the requirement like PROJECT_NAME.FUNCTION1.5. I don't know how to do this elegantly and I tried for 4 hrs with the latex counter with no much success.

Do you have any suggestions?

1
  • Welcome! Please don't post code fragments. They are not very helpful when trying to answer questions or diagnose problems. Instead, please provide the code for a complete minimal document which demonstrates the problem or sets up the question. In this case, you'd want document class, essential packages (tcolorbox, possibly some skins) and then a document environment around your examples.
    – cfr
    Commented Nov 26, 2023 at 4:08

2 Answers 2

1

Steps required to turn code fragments into MWE:

  1. Add \documentclass{article} and document environment.
  2. \usepackage[tcolorblox] -> \usepackage{tcolorblox}.
  3. \usepackage{tcolorblox} -> \usepackage{tcolorbox}.
  4. \newcommand{\makereqtype}[2]{ \newcounter{#2-cnt} } -> \newcommand{\makreqtype}[2]{ \newcounter{#2-cnt} }.
  5. Add \tcbuselibrary{most}.

Please make it easier to help you next time!


I think this does much of what you want. I'm not sure anything will give you a completely robust solution, given the desiderata.

\makereqtype{<name>}{<project>}{<function>}

This works more-or-less as before. <project> and <function> can require a single expansion (or none). For example,

\newcommand* \bob {BoB}
\makereqtype{projA}{PROJECT\_NAME}{FUNCTION1}
\makereqtype{projB}{PROJECT\_NAME}{FUNCTION2}
\makereqtype{studyX}{studyX}{thing1}
\makereqtype{bobb}{\bob}{\bob}

You then need to say

\makereqcrefformats{<name>}{<project>}{<function>}

to generate the cross-referencing formats. Again, arguments 2 and 3 can accommodate simple macros etc. For example,

\makereqcrefformats{projA}{PROJECT\_NAME}{FUNCTION1}
\makereqcrefformats{projB}{PROJECT\_NAME}{FUNCTION2}
\makereqcrefformats{studyX}{studyX}{thing1}
\makereqcrefformats{bobb}{\bob}{\bob}

You can then use

\begin{<name>}[label=<label>]
    ....
\end{<name>}

as before to generate the requirements themselves and \cref{} and friends to get cross-references in the format you require. For example,

\begin{projA}[label=req:pfa]
  requirement stuff
\end{projA}
\begin{projA}[label=req:pfc]
  requirement stuff
\end{projA}
\begin{projA}[label=req:pfb]
  requirement stuff
\end{projA}
\begin{projB}[label=req:pba]
  xx
\end{projB}
\begin{projB}[label=req:pbb]
  xx
\end{projB}
\begin{studyX}[label=req:sxa]
  xx
\end{studyX}
\begin{studyX}[label=req:sxb]
  xx
\end{studyX}
\begin{bobb}[label=req:boba]
  xx
\end{bobb}
\begin{bobb}[label=req:bobb]
  xx
\end{bobb}


Refer to \cref{req:pfa}.
\Cref{req:pfa,req:pfb} must be satisfied \emph{prior} to birth for the eligibility criteria to be met.


\Cref{req:pbb,req:pba,req:sxa,req:sxb,req:boba,req:bobb} show nothing whatsoever.

produces the following result

tailored cross-referencing

\documentclass{article}
% ateb https://tex.stackexchange.com/a/702340/ i gwestiwn Jhonathan Asimov: https://tex.stackexchange.com/q/702283/
\usepackage{tcolorbox}
\tcbuselibrary{most}
\usepackage{cleveref}

\ExplSyntaxOn
\cs_new_protected:Nn \makereq_crefformats:nnn
{
  \crefformat{#1}{##2#2.#3.##1##3}
  \Crefformat{#1}{##2#2.#3.##1##3}
  \crefrangeformat{#1}{#2.#3.##3##1##4--##5##2##6}
  \Crefrangeformat{#1}{#2.#3.##3##1##4--##5##2##6}
  \crefmultiformat{#1}{#2.#3.##2##1##3}{ ~ and~##2##1##3}{, ~ ##2##1##3}{ ~ and~##2##1##3}
  \Crefmultiformat{#1}{#2.#3.##2##1##3}{ ~ and~##2##1##3}{, ~ ##2##1##3}{ ~ and~##2##1##3}
  \crefrangemultiformat{#1}{#2.#3.##3##1##4--##5##2##6}{ ~ and~##3##1##4--##5##2##6}{, ~ ##3##1##4--##5##2##6}{ ~ and~##3##1##4--##5##2##6}
  \Crefrangemultiformat{#1}{#2.#3.##3##1##4--##5##2##6}{ ~ and~##3##1##4--##5##2##6}{, ~ ##3##1##4--##5##2##6}{ ~ and~##3##1##4--##5##2##6}
}
\cs_generate_variant:Nn \makereq_crefformats:nnn { noo }
\cs_new_eq:NN \makereqcrefformats \makereq_crefformats:noo
\ExplSyntaxOff

\NewDocumentCommand \makereqtype { m  m m }
{% ateb https://tex.stackexchange.com/a/702340/ i gwestiwn Jhonathan Asimov: https://tex.stackexchange.com/q/702283/
  \NewTColorBox
  [
    auto counter,
    crefname={#2.#3}{#2.#3},
    Crefname={#2.#3}{#2.#3},
%     /tcb/label type=#1,
%     /tcb/label is label,
  ]{#1}{ O {} }
  {%
    boxrule=0pt,
    titlerule=0pt,
    coltitle=black,
    colbacktitle=black!5,
    colback=black!5,
    sharp corners,
    enhanced,
    borderline west={1pt}{0pt}{black},
    title={#2.\MakeUppercase{#3}.\thetcbcounter},
    fonttitle=\ttfamily,
    ##1,
  }%
}
\begin{document}
\newcommand* \bob {BoB}
\makereqtype{projA}{PROJECT\_NAME}{FUNCTION1}
\makereqtype{projB}{PROJECT\_NAME}{FUNCTION2}
\makereqtype{studyX}{studyX}{thing1}
\makereqtype{bobb}{\bob}{\bob}
\makereqcrefformats{projA}{PROJECT\_NAME}{FUNCTION1}
\makereqcrefformats{projB}{PROJECT\_NAME}{FUNCTION2}
\makereqcrefformats{studyX}{studyX}{thing1}
\makereqcrefformats{bobb}{\bob}{\bob}

\begin{projA}[label=req:pfa]
  requirement stuff
\end{projA}
\begin{projA}[label=req:pfc]
  requirement stuff
\end{projA}
\begin{projA}[label=req:pfb]
  requirement stuff
\end{projA}
\begin{projB}[label=req:pba]
  xx
\end{projB}
\begin{projB}[label=req:pbb]
  xx
\end{projB}
\begin{studyX}[label=req:sxa]
  xx
\end{studyX}
\begin{studyX}[label=req:sxb]
  xx
\end{studyX}
\begin{bobb}[label=req:boba]
  xx
\end{bobb}
\begin{bobb}[label=req:bobb]
  xx
\end{bobb}


Refer to \cref{req:pfa}.
\Cref{req:pfa,req:pfb} must be satisfied \emph{prior} to birth for the eligibility criteria to be met.


\Cref{req:pbb,req:pba,req:sxa,req:sxb,req:boba,req:bobb} show nothing whatsoever.
\end{document}
5
  • Thank you very much, sorry for the mistakes and incomplete MWE. For the referencing you use the tag requirement, requirements,..., but that is not what I need: the problem is that the reference name should be the full title of the tcolorbox like PRJNAME.FUNCTION1.1, how can I do that? Moreover the streamlined solution is beautiful, thank you! But I don't understand how to instantiate different boxes where the PROJECTNAME and FUNCTIONAME change: do I change the first parameter of the \makereqtype command? (In the last example you used the same one projA I'm confused) Commented Nov 27, 2023 at 10:33
  • Re the second question: yes, you change projA. Each time you use \makereqtype, you pick a different shorthand. So projA for PROJECTNAME/FUNCTION1, myproj for OTHERNAME/OTHERFUNCTION, projB for PROJECTNAME/FUNCTION2 etc. Each time you use \makereqtype, the first argument should be new. Re the first question: you can get the name using cleveref, I believe. I'll try to look later.
    – cfr
    Commented Nov 27, 2023 at 13:35
  • I found a problem with \makereqpurify. As I was saying I would like to pass latex "functions" to the \makereqtype parameters. In this case an alias to the projectname (\newcommand{\projectname}{foo}). If i run \makereqtype{test}{\projectname}{function} it doesn't work. Commented Nov 27, 2023 at 15:33
  • @JhonathanAsimov You can actually just get rid of the \makereqpurify stuff with the second approach because you're not using it to create the name of the environment or label type. If you know what you need at the start, you can define various label types and get the output you want from \cref. But I'm not sure you can automate this as trying to define them inside \makereqtype just doesn't work. (Grouping? I didn't think \NewDocumentCommand would create a group ....)
    – cfr
    Commented Nov 27, 2023 at 18:37
  • @JhonathanAsimov See rewritten answer above. I don't think you'll get anything which fully satisfies both (1) and (2), depending on exactly what you mean by (1). (2) is entirely possible and (1) can be supported straightforwardly in a limited range of cases, but you can't have something you can throw just anything at unless you are prepared to package it carefully before throwing. You want to use it in cases where some kinds of things aren't allowed. But simple macros are certainly doable. Unless you hijack \the or something.
    – cfr
    Commented Nov 28, 2023 at 0:03
1

I'd add an optional argument for the label needed in cross-references.

Note that you should use \MakeUppercase, not \uppercase.

\documentclass{article}
\usepackage[most]{tcolorbox}

\newcommand{\makereqtype}[2]{%
  \newcounter{#2-cnt}%
  %\setcounter{#2-cnt}{-1}% uncomment if you want to start from 0
}

%param1: project name
%param2: function
\NewDocumentEnvironment{requirement}{mmo}{%
  \begin{tcolorbox}[
    boxrule=0pt,
    frame hidden,
    sharp corners,
    enhanced,
    borderline west={1pt}{0pt}{black}
  ]
  \ExpandArgs{c}\renewcommand{the#2-cnt}{#1.\MakeUppercase{#2}.\arabic{#2-cnt}}%
  \refstepcounter{#2-cnt}\IfValueT{#3}{\label{#3}}%
  \texttt{\UseName{the#2-cnt}}\\
}{\end{tcolorbox}}

%That is invoked in the text like this:
\begin{document}

\makereqtype{PROJECT\_NAME}{FUNCTION1} %% do this only once

%% For each requirement of functionality FUNCTION1 do:
\begin{requirement}{PROJECT\_NAME}{FUNCTION1}
requirement stuff
\end{requirement}

\begin{requirement}{PROJECT\_NAME}{FUNCTION1}[foo]
requirement stuff
\end{requirement}

\ref{foo}

\end{document}

If you want the numbering to start from 0, uncomment the line in the definition of \makereqtype.

It makes sense, in this application, to use the expandable version of \MakeUppercase.

\documentclass{article}
\usepackage[most]{tcolorbox}

\newcommand{\makereqtype}[2]{%
  \newcounter{#2-cnt}%
  %\setcounter{#2-cnt}{-1}% uncomment if you want to start from 0
}

\ExplSyntaxOn
\cs_new_eq:NN \ExpMakeUppercase \text_uppercase:n
\ExplSyntaxOff

%param1: project name
%param2: function
\NewDocumentEnvironment{requirement}{mmo}{%
  \begin{tcolorbox}[
    boxrule=0pt,
    frame hidden,
    sharp corners,
    enhanced,
    borderline west={1pt}{0pt}{black}
  ]
  \ExpandArgs{c}\renewcommand{the#2-cnt}{#1.\ExpMakeUppercase{#2}.\arabic{#2-cnt}}%
  \refstepcounter{#2-cnt}\IfValueT{#3}{\label{#3}}%
  \texttt{\UseName{the#2-cnt}}\\
}{\end{tcolorbox}}

%That is invoked in the text like this:
\begin{document}

\makereqtype{PROJECT\_NAME}{FUNCTION1} %% do this only once

%% For each requirement of functionality FUNCTION1 do:
\begin{requirement}{PROJECT\_NAME}{FUNCTION1}
requirement stuff
\end{requirement}

\begin{requirement}{PROJECT\_NAME}{FUNCTION1}[foo]
requirement stuff
\end{requirement}

\ref{foo}

\end{document}

enter image description here

You may want to add

\newcommand{\projref}[1]{\texttt{\ref{#1}}}

and call the cross-reference as \projref{foo}.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .