6

I am building a catalog of items and would like to ensure that my fields always display in a certain order (for the sakes of argument lets us say in the order "Intentory Number, Weight, Diameter" even if I am entering the data in a different order. I would like to make this display in the order I have defined the keys in and not in the order I enter the keys in. Is this possible?

\documentclass{article}
\usepackage{keyval}

\newcommand{\catalogueentry}[1]{\setkeys{entrydetails}{#1}}
\makeatletter
\define@key{entrydetails}{intentorynumber}{\noindent \textbf{Intentory number:} \emph{#1}\\}
\define@key{entrydetails}{weight}{\noindent \textbf{Weight:} \emph{#1}\\}
\define@key{entrydetails}{diameter}{\noindent \textbf{Diameter:} \emph{#1}\\}
\makeatother

\begin{document}

\catalogueentry{intentorynumber=0001,
diameter= very small,
weight=really heavy,
}

\end{document}
gman
  • 1,807
  • Welcome to TeX.SX! Your definition of the keys is not very good, in my point of view. –  Jul 08 '15 at 14:55
  • By the way: Shouldn't it read inventory rather than intentory? –  Jul 08 '15 at 20:19

2 Answers2

3

The basic feature of a keyvalue interface is not just to provide the keys and assign some values to them but also to store the key values and process (say typeset their) values later on.

You should separate between defining data and processing them, as usual.

The \setkeys macro is for identifying the keys (which one has been given at all?) and stores them to \KV... macros. Those values can be used arbitrarily often inside thecatalogueentry` command to do some (weird) things with them.

\documentclass{article}
\usepackage{keyval}

\newcommand{\catalogueentry}[1]{%
\setkeys{entrydetails}{#1}
\noindent \textbf{Intentory number:} \emph{\KVIntentoryNumber} 

\noindent \textbf{Weight:} \emph{\KVWeight}

\noindent \textbf{Diameter:} \emph{\KVDiameter}
}


\makeatletter
\define@key{entrydetails}{intentorynumber}{\def\KVIntentoryNumber{#1}}
\define@key{entrydetails}{weight}{\def\KVWeight{#1}}
\define@key{entrydetails}{diameter}{\def\KVDiameter{#1}}
\makeatother

\begin{document}

\catalogueentry{intentorynumber=0001,
diameter= very small,
weight=really heavy,
}

\catalogueentry{intentorynumber=0002,
weight={${2\times 10^{30}\;}$ kg},   % Sorry Joseph, no \SI... here :-P
diameter= very large
}

\end{document}

enter image description here

Update

As long as no grouping is involved, the key value macros are global, i.e. the content from one call of the outer command to the next one, the values persist, unless overwritten by a new specification.

This can be changed with grouping.

Anyway (and this was missing from the first version): If the key is not given at all, the relevant key macro isn't defined and a call to \KV... will fail. Using \ifdef{\KV...}{true branch}{false branch} will prevent this.

\documentclass{article}
\usepackage{keyval}
\usepackage{siunitx} % Just to make Joseph Wright happy :-P
\usepackage{etoolbox}

\newcommand{\catalogueentry}[1]{%
\begingroup
\setkeys{entrydetails}{#1}
\ifdef{\KVIntentoryNumber}{%
\noindent \textbf{Intentory number:} \emph{\KVIntentoryNumber} %
}{}%

\ifdef{\KVWeight}{%
\noindent \textbf{Weight:} \emph{\KVWeight}%
}{}%

\ifdef{\KVDiameter}{%
\noindent \textbf{Diameter:} \emph{\KVDiameter}%
}{}%
\endgroup
}


\makeatletter
\define@key{entrydetails}{intentorynumber}{\def\KVIntentoryNumber{#1}}
\define@key{entrydetails}{weight}{\def\KVWeight{#1}}
\define@key{entrydetails}{diameter}{\def\KVDiameter{#1}}
\makeatother

\begin{document}

\catalogueentry{intentorynumber=0001,
diameter= very small,
weight=really heavy,
}


\catalogueentry{intentorynumber=0002,
weight={\SI{2d30}{kg}},
diameter= very large
}

\catalogueentry{intentorynumber=0003,
diameter={\SI{13.7d9}{ly}}
}



\end{document}

enter image description here

  • Please at least weight = \ensuremath{2 \times 10^{30}\,\mathrm{kg}} :-) (If you are setting up code that will be very general, \ensuremath is probably slightly preferable to explicit math mode.) – Joseph Wright Jul 08 '15 at 19:39
  • Thank you: i wanted to ask further; is there a method by which each key might be forgotten each time? If in the next catalog entry, for example I do not include a weight, it will print the last weight inputted but this would be wrong. it may be the case that the entry should just have no weight. –  Jul 08 '15 at 19:38
  • @JosephWright: I wanted to avoid to include 'overheight' :-P –  Jul 08 '15 at 19:42
  • @tuthmoses: Yes, I will update my solution, but this would mean you have to ask if a key has been specified or not –  Jul 08 '15 at 19:43
  • @JosephWright: Better? ;-) –  Jul 08 '15 at 20:19
  • @tuthmoses: See my update please. –  Jul 08 '15 at 20:19
2

The idea is the same as in the other fine answer, but I prefer the expl3 style key-value syntax.

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\catalogueentry}{m}
 {
  \group_begin:
  \keys_set:nn { tuthmoses/catalogue } { #1 }
  \tuthmoses_catalogue_entry:VVV
   \l_tuthmoses_inventory_tl
   \l_tuthmoses_weight_tl
   \l_tuthmoses_diameter_tl
  \group_end:
 }

\keys_define:nn { tuthmoses/catalogue }
 {
  inventorynumber .tl_set:N  = \l_tuthmoses_inventory_tl,
  weight          .tl_set:N  = \l_tuthmoses_weight_tl,
  diameter        .tl_set:N  = \l_tuthmoses_diameter_tl,
  inventorynumber .initial:n = \tuthmoses_error:n { Inventory~number },
  weight          .initial:n = \tuthmoses_error:n { Weight },
  diameter        .initial:n = \tuthmoses_error:n { Diameter },
 }

\cs_new_protected:Nn \tuthmoses_catalogue_entry:nnn
 {
  \par\noindent
  \textbf{Inventory~Number:} ~ #1 \\*
  \textbf{Weight:} ~ #2 \\*
  \textbf{Diameter:} ~ #3
  \par
 }
\cs_generate_variant:Nn \tuthmoses_catalogue_entry:nnn { VVV }

\cs_new_protected:Nn \tuthmoses_error:n
 {
  \msg_error:nnn { tuthmoses/catalogue } { Missing~value } { #1 }
 }

\msg_new:nnnn { tuthmoses/catalogue } { Missing~value }
 {
  Missing~value~for~#1
 }
 {
  You~must~specify~a~value~for~#1
 }

\ExplSyntaxOff

\begin{document}

\catalogueentry{
  inventorynumber=0001,
  diameter= very small,
  weight=really heavy,
}

\catalogueentry{
  diameter= very small,
  inventorynumber=0002,
  weight=really heavy,
}

\catalogueentry{
  diameter= very small,
  weight=really heavy,
}

\end{document}

The main command opens a group to make changes to the values local; then it sets the keys from the argument and uses the function \tuthmoses_catalogue_entry:VVV with the variables storing the values as argument.

Next we define the keys with their initial value, which is issuing an error.

The main internal function does the typesetting using #1, #2 and #3; a variant of it is defined for using variables instead of explicit arguments.

Finally the error reporting function is defined; it's essentially syntactic sugar for \msg_error:nnn. The actual error message ends the code part.

Output

enter image description here

Error message from the wrong entry

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! tuthmoses/catalogue error: "Missing value"
! 
! Missing value for Inventory number
! 
! See the tuthmoses/catalogue documentation for further information.
! 
! For immediate help type H <return>.
!...............................................  

l.70 }

? h
|'''''''''''''''''''''''''''''''''''''''''''''''
| You must specify a value for Inventory number
|...............................................
egreg
  • 1,121,712