5

I'm trying to write tags to include document info which can be declared in the preamble then included in a title page using \@institution or \@module, similar to how LaTeX already includes \title{} to get \@title.

I need a command which has an optional "module number" and can be declared by \module[PH588]{Mathematical Techniques} in the preamble, to form tags like \@mod@no and \@mod@title (or similar) to be used in the title page as

{\Large \mod@no: \@mod@title \par}

and produce "PH588: Mathematical Techniques" in a large font.

I am new to this whole macro business and am only fully comfortable with basics like \newcommand. For other information I've used

\newcommand{\department}[1]{\renewcommand\@dept{#1}}
    \newcommand{\@dept}{}

to define each title element.

My attempts thus far (which have been fruitless) are along the lines of:

1)

\def\module[#1]#2{\gdef\@module[#1]{#2}}
    \def\@module{}

2)

\def\module{\@ifnextchar[{\@module@wno}{\@module@wono}}
    \newcommand{\@module}{}
        \def\@module[#1]#2{#1: #2}
        \def\@module#1{#1}

3)

\newcommand{\module}[2][no module number]{\@ifnextchar[{\renewcommand\@module@no[2]{#1}}{\renewcommand\@module}}
    \def\@module@no[#1]#2{#1}
    \def\@module#1{#1}
    \newcommand\@module@no[#1]#2{#1: #2}
    \newcommand\@module#1{#1}

These are all between \makeatletter and \makeatother.

As you can see I have very little idea what I'm doing, so if you could provide a simple explanation of how each part of your code does what it's doing and why that would really help me out!

Thanks in advance!

  • Sorry, the question is unclear to me. Why fruitless? – user31729 May 9 '15 at 23:17
  • You are thinking too complicated, step back a little. Looking at package or kernel code isn't necessary a sign for good coding. Simply do as in your very first snippet and add \renewcommand{\moduleno}{#1}, which is the optional argument. The mandatory argument is now #2. – Johannes_B May 9 '15 at 23:21
  • Most probably, the \@module stuff should be 'renewcommand – user31729 May 9 '15 at 23:22
  • If you think about adding a star feature somewhere, better familiarize yourself with package xparse, it will come in handy. And it might be handy here. – Johannes_B May 9 '15 at 23:23
  • 1
    \newcommand\a[2][x]{#1-#2} will define \a so that \a{b} expands to x-b and \a[y]{b} to y-b. – Qrrbrbirlbel May 9 '15 at 23:25
3

Something with the hard way using \@ifnextchar and the easy way with xparse

\documentclass{article}

\usepackage{xcolor}
\usepackage{xparse}

\makeatletter

\providecommand{\@module@no}{}
\providecommand{\@module@title}{}


\newcommand{\module}{%
  \@ifnextchar[{\module@@opt}{\module@@noopt}
}

\newcommand{\module@@opt}[2][no module number]{%
\renewcommand{\@module@no}{#1}%
\renewcommand{\@module@title}{#2}%
}

\newcommand{\module@@noopt}[1]{%
  \module@@opt{#1}%
}


%\@onlypreamble{\module}


\NewDocumentCommand{\Module}{o+m}{%
  \IfValueTF{#1}{%
    \renewcommand{\@module@no}{#1}%
  }{%
    \renewcommand{\@module@no}{no module number}%
  }%
  \renewcommand{\@module@title}{#2}%
}


\newcommand{\printmoduleinfo}{%
{\large \textbf{\@module@no} \textsc{\@module@title}}%
}



\makeatother




\begin{document}

\module[The Fellowship of the Ring]{The Lord Of the Rings}


\printmoduleinfo

\module{The Lord Of the Rings}

\printmoduleinfo

\fbox{\textcolor{blue}{And now again with the xparse stuff}}

\Module[The two Towers]{The Lord Of the Rings}

\printmoduleinfo

\Module{The Lord Of the Rings}

\printmoduleinfo


\end{document}

enter image description here

  • You should group that large – Johannes_B May 9 '15 at 23:30
  • @Johannes_B: Principally yes, but it's only a demo command, since there is nothing else known – user31729 May 9 '15 at 23:32
  • Sure, still, should be grouped. The fiont will else be large, or fett or whatever for the rest of the doc. Though not really necessarry for the example, it's a bit of best-practice. – Johannes_B May 9 '15 at 23:38
  • @Johannes_B: And I don't care :-P – user31729 May 9 '15 at 23:39
  • @ChristianHupfer you answered one of my questions the other day, too! I found the xparse part a little hard to follow but I'll look in to using that package for future endeavours. Thank you! – Harry Smith May 9 '15 at 23:46
1

The right solution is

0)

\def\module[#1]#2{\gdef\mod@no{#1}\gdef\mod@title{#2}}

This defines \module macro for the usage \module[num]{text}. This macro defines \mod@no as num and \mod@title as text. It means that you can use later \mod@no which expands to num and \mod@title which expands to text. This is exactly, what you need.

Your bad attepts:

1)

\def\module[#1]#2{\gdef\@module[#1]{#2}}
\def\@module{}

After \module[num]{text} the macro \@module is defined with mandatory argument [num] (i.e. if you type something different from exactly \@module[num] then TeX will print an error). This very curious macro expands to the text. The setting \@module to empty macro via \def at line two is redundant.

2)

\def\module{\@ifnextchar[{\@module@wno}{\@module@wono}}
\newcommand{\@module}{}
\def\@module[#1]#2{#1: #2}
\def\@module#1{#1}

This is overcomplicated and bad. This defines \module as macro which looks to the next token. If it is [ then \@module@wno is executed else \@module@wono is executed. But these macros are not defined. Next, the \@module macro is defined as empty (the same as \def\@module{}). Next, this macro \@module is redefined as macro with one parameter in [...] and second in {}, The \@module[num]{text} expands to num: text. Finally, the \@module macro is redefined again, now with one parameter in {}, the \@module{text} expands to text. Why there are three definitions of the same macro? Only the last win. Why there are not defined the \@module@wno, \@module@wono macros?

3)

\newcommand{\module}[2][no module number]{%
    \@ifnextchar[{\renewcommand\@module@no[2]{#1}}{\renewcommand\@module}}
\def\@module@no[#1]#2{#1}
\def\@module#1{#1}
\newcommand\@module@no[#1]#2{#1: #2}
\newcommand\@module#1{#1}

This defines \@module@no and @module as an obscure macros via \def. Then the same macros are redefined via \newcommand, but \newcommand prints error because A) the macros are already defined and B) here is bad syntax for \newcommand. At the first line, the \module is defined via \newcommand as a macro with one optional parameter and one mandatory parameter, example of usage \module[opt]{text} or \module{text}. The second example behaves as \module[no module number]{text}. This macro looks to the next token and if it is [ (i.e. the usage is \module[opt]{text}[) then it redefines \@module@no else it redefines \@module but does nothing more.

I tried to look at your code by TeX's eyes in order to show that all these codes are absurd. I recommend you to study how \def and macros in TeX behave. After such study, you will find out that the accepted solution is overcomplicated too.

  • Did you notice, that I used \NewDocumentCommand as well to shorten the syntax? – user31729 May 10 '15 at 15:36
  • It seems that your thorough and useful explanations will be just as thorough and useful if you leave only the facts, and delete the editorial references to things being bad and absurd. @HarrySmith clearly put genuine effort into the demonstrated solutions; what's the point of shaming him for mistakes? – LSpice May 11 '15 at 19:50
  • @LSpice I don't shame him for mistakes because he know that there are mistakes (see the text: "As you can see I have very little idea what I'm doing, so if you could provide a simple explanation..."). I only provided the simple explanation as mentioned in the question. – wipet May 11 '15 at 20:23
1

It's very easy, with xparse, to define a command that prints what you want:

\usepackage{xparse}

\NewDocumentCommand{\module}{om}{%
  {\Large\IfValueT{#1}{#1: }#2\par}%
}

The {#1: } part is printed if you call \module[PH588]{Mathematical Techniques}, but not with the call \module{Mathematical Techniques}

If you need the optional module number and the module title in other places, then you can follow the same pattern:

\usepackage{xparse}
\makeatletter
\newcommand{\@module@no}{} % initialize
\newcommand{\@module}{} % initialize

\NewDocumentCommand{\module}{om}{%
  \IfValueTF{#1}
    {% there is a module number
     \renewcommand{\@module@no}{#1}%
    }
    {% there is no module number
     \renewcommand{\@module@no}{}%
    }%
  \renewcommand{\@module}{#2}%
  % print the module title
  {\Large\IfValueT{#1}{#1: }#2\par}%
}
\makeatother

You'll be able to discriminate between the module number being currently available with an emptyness test such as

\if\relax\detokenize\expandafter{\@module@no}\relax
  <code for no module number>%
\else
  <code for available module number>%
\fi
  • I suppose, it should read \IfValueTF in your first code snippet? – user31729 May 10 '15 at 16:20
  • @ChristianHupfer No, why? If no optional argument is given, \IfValueT returns false and does nothing. – egreg May 10 '15 at 16:33
  • Apparently I have missed that there is \IfValueT either – user31729 May 10 '15 at 16:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.