Beim Erstellen einer eigenen Dokumentenklasse ist mir aufgefallen, dass entgegen der Beschreibung im clsguide Optionen, mit denen die Klasse aufgerufen wird, in bestimmen Fällen an die Basisdokumentenklasse weitergegeben werden, selbst wenn sie als klasseneigene Optionen definiert wurden. Das folgende Minimalbeispiel ohne praktische Anwendung verdeutlicht das Problem. Dokumentenklasse: Open in Online-Editor
\NeedsTeXFormat{LaTeX2e} \ProvidesClass{testklasse} \newcommand{\Optionserkennung}{Es wurde keine klasseneigene Option erkannt.} \DeclareOption{landscape}{\renewcommand{\Optionserkennung}{Die klasseneigene Option landscape wurde erkannt.}} \DeclareOption*{\PassOptionsToClass{\CurrentOption}{scrartcl}} \ProcessOptions\relax \LoadClass{scrartcl} Dokument, das die Klasse verwendet: Open in Online-Editor
\documentclass[landscape]{testklasse} \usepackage{blindtext} \begin{document} \Optionserkennung \blindtext \end{document} In der Ausgabe erkennt man, dass die Option landscape zwar als klasseneigene Option erkannt wurde, aber trotzdem an die Klasse scrartcl weitergegeben wurde. Das gleiche passiert entsprechend auch bei der Option pagesize, nicht aber beispielsweise bei der Option leqno und auch nicht mit der Basisdokumentenklasse article. Wie lässt sich dieses Verhalten erklären? (Und welche Wirkung hat eigentlich der relax-Befehl nach ProcessOptions?) gefragt 07 Apr '15, 19:05 Cletus |
Wie @esdd in ihrem Kommentar schon richtig bemerkt hat, ist Option Will man nun also, dass eine Option aus Open in Online-Editor
\RequirePackage{filecontents} \begin{filecontents}{testklasse.cls} \ProvidesClass{testklasse}[2014/04/25 demonstation objekt only] \providecommand*{\removefromglobaloptions}[1]{% #1 ist die unerwünschte Option \begingroup \let\reserved@a\@classoptionslist% \reserved@a bekommt den Inhalt der globalen Optionen \let\@classoptionslist\@empty% die globalen Optionen werden gelöscht \edef\reserved@b{#1}% \expandafter\@for\expandafter\reserved@a\expandafter:\expandafter=% \reserved@a\do{% jede ehemals globale Option \ifx\reserved@a\reserved@b\else% die nicht der unerwünschten Option entspricht % wieder der Liste der globalen Optionen hinzufügen: \ifx\@classoptionslist\@empty\global\let\@classoptionslist\reserved@a \else\expandafter\g@addto@macro\expandafter\@classoptionslist \expandafter{\expandafter,\reserved@a}\fi \fi }% \endgroup } \DeclareOption{twoside}{\typeout{Option `twoside' used.}\removefromglobaloptions{twoside}} \DeclareOption{titlepage}{\typeout{Option `titlepage' used.}\removefromglobaloptions{titlepage}} \DeclareOption{landscape}{\typeout{Option `landscape' used.}\removefromglobaloptions{landscape}} \DeclareOption*{\PassOptionsToClass{\CurrentOption}{scrartcl}} \ProcessOptions\relax \LoadClass{scrartcl} \end{filecontents} \documentclass[twoside,titlepage,landscape,ngerman]{testklasse} \usepackage{babel} \usepackage{mwe} \begin{document} \title{Test} \author{Me} \maketitle \tableofcontents \Blinddocument \end{document} Würde man nun später im Dokument beispielsweise Open in Online-Editor
\RequirePackage{filecontents} \begin{filecontents}{testklasse.cls} \ProvidesClass{testklasse}[2014/04/25 demonstation objekt only] \providecommand*{\removefromglobaloptions}[1]{% \begingroup \let\reserved@a\@classoptionslist \let\@classoptionslist\@empty \edef\reserved@b{#1}% \expandafter\@for\expandafter\reserved@a\expandafter:\expandafter=% \reserved@a\do{% \ifx\reserved@a\reserved@b\else \ifx\@classoptionslist\@empty\global\let\@classoptionslist\reserved@a \else\expandafter\g@addto@macro\expandafter\@classoptionslist \expandafter{\expandafter,\reserved@a}\fi \fi }% \endgroup } \let\all@classoptionslist\@classoptionslist \DeclareOption{twoside}{\typeout{Option `twoside' used.}\removefromglobaloptions{twoside}} \DeclareOption{titlepage}{\typeout{Option `titlepage' used.}\removefromglobaloptions{titlepage}} \DeclareOption*{\PassOptionsToClass{\CurrentOption}{scrartcl}} \ProcessOptions\relax \LoadClass{scrartcl} \let\@classoptionslist\all@classoptionslist \end{filecontents} \documentclass[twoside,titlepage,ngerman]{testklasse} \usepackage{babel} \usepackage{geometry} \usepackage{mwe} \begin{document} \title{Test} \author{Me} \maketitle \tableofcontents \Blinddocument \end{document} Aber: Man kann auf diese Weise nicht verhindern, dass jemand per BTW: Ich bin mir bewusst, dass es für das Entfernen von Optionen aus der aktuellen Liste schnelleren Code gibt. Obiger Code erscheint mir aber nicht nur recht zuverlässig, sondern auch gerade noch verständlich. Irgendwelche Pattern-Match-Argument-Tricks sind das hingegen nicht. Deshalb habe ich diesen Weg gewählt. @saputello Danke :-)
(25 Apr '15, 19:00)
esdd
|
Auch wenn die Option nicht an die Basisdokumentenklasse weitergegeben wird, ist sie eine globale Option für Pakete.
scrartcl
lädt das Pakettypearea
, welches die Optionlandscape
kennt und deshalb für die Ausgabe des Dokuments im Querformat sorgt. Und auchpagesize
ist eine Option des Paketestypearea
.Von
\ProcessOptions
gibt es auch eine Sternform. Das\relax
wird verwendet, um die Suche nach diesem Stern zu verhindern.Das klingt plausibel. Allerdings finde ich dieses Verhalten etwas problematisch, da man als „Weiterverwerter“ einer Dokumentenklasse nicht unbedingt weiß, welche Pakete diese aufruft. (In der objektorientierten Programmierung wäre so etwas inakzeptabel, Stichwort Kapselung.)
Klassen bei LaTeX haben nichts mit den Klassen in objektorientierten Sprachen zu tun. Man sollte das nicht in einen Topf werfen. Die einzige Kapselung und die einzigen Scopes, die TeX kennt, sind Gruppen. Will man LaTeX wirklich verstehen, muss man TeX verstehen. Will man TeX verstehen sollte man sich weniger mit objektorientieren als mit Makro-Sprachen beschäftigen.
Und in der KOMA-Script-Anleitung ist sehr wohl dokumentiert, dass die KOMA-Script-Klassen
typearea
verwenden.