2

When I compile the following code, I expect a "Yes" but I get a "No" instead. Is there something subtle going on or is my method for checking wrong? If so, how can I see which options have been passed to babel? (It's for a class I'm writing.)

\@ifpackageloaded{babel} gives a "Yes", as does \usepackage[english]{babel}.

\documentclass[english]{article}
\usepackage{babel}
\newcommand{\control}{undefined}
\makeatletter
    \@ifpackagewith{babel}{english}
        {\renewcommand{\control}{Yes}}
        {\renewcommand{\control}{No}}
\makeatother

\begin{document}
\control
\end{document}
  • You aren't loading babel with the english option. ;-) Indeed, global options don't appear in the list associated to babel. – egreg Jan 14 '16 at 16:48
  • @egreg Yes but why? Shouldn't global options be passed to every package, babel included? – Arch Stanton Jan 14 '16 at 16:50
  • They are passed, but the macro \opt@babel.sty isn't updated with the global options: it only contains the “local” options. – egreg Jan 14 '16 at 16:50
  • @egreg Is this a subtlety of babel only? I mean, should I always repeat the relevant options when I call babel, even if I declared them in the class too? – Arch Stanton Jan 14 '16 at 16:55
  • No, it's for all packages. – egreg Jan 14 '16 at 17:07
6

When you load a package with

\usepackage[a,b,c]{package}

the macro \opt@package.sty is defined to expand to a,b,c; such a macro is used for \@ifpackagewith. However, global options are not included in the list. So, if the package know the option g and you do

\documentclass[g]{article}

\usepackage[a,b,c]{package}

the option g will be passed to package before the options a, b and c. However the code

\@ifpackagewith{g}{package}{YES}{NO}

will follow the false branch. Unfortunate? Yes.

Can you do something about this? Of course you can, because the global options are stored in \@classoptionslist, but there's no explicit interface for it.

The babel package relies on \date<language> being defined as a check that the language has been loaded, either as a global or a local option.

Here's an expl3 version of \@ifpackagewith that also checks the global options.

\documentclass[english]{article}
\usepackage{babel}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\packageoptionsTF}{mmmm}
 {
  \stanton_package_options:nnTF { #1 } { #2 } { #3 } { #4 }
 }

\cs_new_protected:Nn \stanton_package_options:nnTF
 {
  \clist_map_inline:nn { #2 }
   {
    \clist_if_in:cnTF { opt@#1.sty } { ##1 }
     { #3 } % it's a local option
     {
      \clist_if_in:cnTF { @classoptionslist } { ##1 }
       { #3 } % it's a global option
       { #4 }
     }
   }
}
\ExplSyntaxOff

\newcommand{\control}{undefined}
\newcommand{\ita}{}

\packageoptionsTF{babel}{english}{%
  \renewcommand{\control}{Yes}%
}{%
  \renewcommand{\control}{No}%
}
\packageoptionsTF{babel}{italian}{%
  \renewcommand{\ita}{Yes}%
}{%
  \renewcommand{\ita}{No}%
}

\begin{document}

\control

\ita

\end{document}

The output is

Yes
No

  • Thanks egreg. This ranks among the best pieces of code I've ever stolen from here :-) – Arch Stanton Jan 17 '16 at 0:13
  • @ArchStanton You're welcome! I have even better code on the site, notwithstanding what a fellow chat resident might say. ;-) – egreg Jan 17 '16 at 0:16
  • egreg, I don't understand the code, but I think it only checks if the options are given but not if the package is actually loaded, judging by how it behaves. – Arch Stanton Jan 17 '16 at 20:26
  • @ArchStanton You're right: \@ifpackagewith doesn't balk if the package has not been actually loaded. It's the same for the code I proposed. Probably you want to add the check whether the package has been loaded. – egreg Jan 17 '16 at 20:28
  • Sorry, I thought it did. – Arch Stanton Jan 17 '16 at 20:30

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.