不使用 \newcommand 定义变量

不使用 \newcommand 定义变量

我正在编写发票类,我想tex尽可能保持实际文件干净,以便代码不会吓跑非技术人员。

我的最终目标是在invoice.cls文件中定义一个变量,然后通过一个非常简单干净的命令为其设置一个值main.tex。类似于\address{Street, Number}{ZIP Code Town}{Country}\name{First name}{Last name}\bankDetails{IBAN number}{Bank Swift Code}

请记住,我必须在invoice.cls文件中使用这些变量的值。

目前,我在类文件中定义了一个新命令,并为其提供了一些可选参数。通过调用命令并传递参数,我得到了类似上面的代码。问题是,我需要在多个地方访问名称变量,并且我不希望最终用户必须多次输入他的名字作为参数……最好将这些变量定义在全局,并在需要时访问它们。

就像

\newcommand{\firstName}{John}
\newcommand{\lastName}{Doe}
\newcommand{\name}{\firstName\,\lastName}

但你会明白

\name{John}{Doe}

会干净得多。

答案1

我非常喜欢expl3它的property“变量”功能,即key基于列表的数据存储。只要键的数量不是太大,prop列表就非常方便。

键可能是FirstNameZip

\StoreInvoiceData将给定的键存储为等FirstName=foo,放入属性列表的IBAN=US345342342相关槽中,此处命名。宏的键值接口不能与属性列表的 混淆,尽管后台的存储机制是相同的。名称与属性键名称相同,这不是强制性的,但为了方便记住名称。key\g_sam_invoice_propkeyskey=

指定顺序根本不重要。

例如使用\GetInvoiceData{foo}来提取foo密钥的值。

\documentclass{article}


\usepackage{xparse}

\ExplSyntaxOn
\prop_new:N \g_sam_invoice_prop

\cs_new:Nn \sam_store_property:nn {
  \prop_gput:Nnn \g_sam_invoice_prop {#1} {#2}
}

%Defining key-value interface
 \keys_define:nn {saminvoice} {
    Street .code:n = {\sam_store_property:nn {Street}{#1} },
    Number .code:n = {\sam_store_property:nn {Number}{#1} },
    Zip .code:n = {\sam_store_property:nn {Zip}{#1} },
    Country .code:n = {\sam_store_property:nn {Country}{#1} },
    FirstName .code:n = {\sam_store_property:nn {FirstName}{#1} },    
    SecondName .code:n = {\sam_store_property:nn {SecondName}{#1} },    
    IBAN .code:n = {\sam_store_property:nn {IBAN}{#1} },    
    BIC .code:n = {\sam_store_property:nn {BIC}{#1} },    
  }
\NewDocumentCommand{\StoreInvoiceData}{+m}{
  \prop_gclear:N \g_sam_invoice_prop% Clearing the property list
  % Set the keys
  \keys_set:nn {saminvoice}{#1}
}

\NewDocumentCommand{\GetInvoiceData}{m}{
  \prop_if_in:NnTF \g_sam_invoice_prop {#1} 
  {% True
    \prop_item:Nn \g_sam_invoice_prop {#1}% Extract the key #1 from the property list
  }{% False
    Unknown
  }
}

\ExplSyntaxOff

\begin{document}

\StoreInvoiceData{FirstName=Gandalf,SecondName={The Grey},Zip={The Nine},Country={Middle Earth}, IBAN={MORDOR6.60-34}}


This is an invoice for \GetInvoiceData{FirstName}\ \GetInvoiceData{SecondName} about the manufacturing and delivery of 100 Mage staffs. Please pay to \GetInvoiceData{IBAN}

\end{document}

在此处输入图片描述

检查是否给出密钥的版本

\documentclass{article}


\usepackage{xparse}

\ExplSyntaxOn
\prop_new:N \g_sam_invoice_prop

\cs_new:Nn \sam_store_property:nn {
  \prop_gput:Nnn \g_sam_invoice_prop {#1} {#2}
}

%Defining key-value interface
 \keys_define:nn {saminvoice} {
    Street .code:n = {\sam_store_property:nn {Street}{#1} },
    Number .code:n = {\sam_store_property:nn {Number}{#1} },
    Zip .code:n = {\sam_store_property:nn {Zip}{#1} },
    Country .code:n = {\sam_store_property:nn {Country}{#1} },
    FirstName .code:n = {\sam_store_property:nn {FirstName}{#1} },    
    SecondName .code:n = {\sam_store_property:nn {SecondName}{#1} },    
    IBAN .code:n = {\sam_store_property:nn {IBAN}{#1} },    
    BIC .code:n = {\sam_store_property:nn {BIC}{#1} },    
    CompanyName .code:n= {\sam_store_property:nn {CompanyName}{#1} },
    ClientName .code:n= {\sam_store_property:nn {ClientName}{#1} }
  }
\NewDocumentCommand{\StoreInvoiceData}{+m}{
  \prop_gclear:N \g_sam_invoice_prop% Clearing the property list
  % Set the keys
  \keys_set:nn {saminvoice}{#1}
}

\NewDocumentCommand{\GetInvoiceData}{m}{
  \prop_if_in:NnTF \g_sam_invoice_prop {#1} 
  {% True
    \prop_item:Nn \g_sam_invoice_prop {#1}% Extract the key #1 from the property list
  }{% False
    Unknown
  }
}

% Normally better with a \prg_new_condiditional:, but for simplicity

% Check if the field is given and execute #2 for true case, otherwise #3
\NewDocumentCommand{\IfInvoiceFieldGivenTF}{m+m+m}{%
  \prop_if_in:NnTF \g_sam_invoice_prop {
    #1% Check to check
  }{% True #2
    #2
  }{% False
    #3
  }
}% End of \IfInVoiceFieldGivenT


% Do something only if #1 is given 
\NewDocumentCommand{\IfInvoiceFieldGivenT}{m+m}{%
  \prop_if_in:NnT \g_sam_invoice_prop {
    #1% Check to check
  }{% True #2
    #2
  }%
}% End of \IfInVoiceFieldGivenT



\ExplSyntaxOff

\begin{document}

\StoreInvoiceData{FirstName=Gandalf,SecondName={The Grey},Zip={The Nine},Country={Middle Earth}, IBAN={MORDOR6.60-34},CompanyName={LembasBread Ltd.}, ClientName={Elrond}}


This is an invoice for \GetInvoiceData{FirstName}\ \GetInvoiceData{SecondName} about the manufacturing and delivery of 100 Mage staffs. Please pay to \GetInvoiceData{IBAN}

\textbf{Long version:}

\IfInvoiceFieldGivenTF{CompanyName}{%
  \GetInvoiceData{CompanyName} c/o \GetInvoiceData{ClientName}
}{%
  \GetInvoiceData{ClientName}%
}%

\textbf{Short version:}

\IfInvoiceFieldGivenT{CompanyName}{%
  \GetInvoiceData{CompanyName} c/o{}% Extra space on purpose here
}
\GetInvoiceData{ClientName}

Clearing Data

\StoreInvoiceData{FirstName=Gandalf,SecondName={The Grey},Zip={The Nine},Country={Middle Earth}, IBAN={MORDOR6.60-34},ClientName={Elrond}}


\textbf{Long version:}

\IfInvoiceFieldGivenTF{CompanyName}{%
  \GetInvoiceData{CompanyName} c/o \GetInvoiceData{ClientName}
}{%
  \GetInvoiceData{ClientName}%
}%

\textbf{Short version:}

\IfInvoiceFieldGivenT{CompanyName}{%
  \GetInvoiceData{CompanyName} c/o{}% Extra space on purpose here
}
\GetInvoiceData{ClientName}


\end{document}

在此处输入图片描述

答案2

看一下数据的定义\maketitle

\def\title#1{\gdef\@title{#1}}
\def\@title{\@latex@error{No \noexpand\title given}\@ehc}
\def\author#1{\gdef\@author{#1}}
\def\@author{\@latex@warning@no@line{No \noexpand\author given}}
\def\date#1{\gdef\@date{#1}}
\gdef\@date{\today}

\title{My Title}存储My Title在全局宏中\@title。后者用于\maketitle。如果用户忘记调用\title\@title则以抛出错误消息的方式初始化。类文件将\ClassError{class name}{Error message}代替使用\@latex@error。示例:

\ProvidesClass{foobar}[2017/08/05 v1.0 ...]
...
\newcommand*{\name}[2]{%
  \gdef\@firstname{#1}%
  \gdef\@lastname{#2}%
}
\def\@firstname{%
  \ClassError{foobar}{No \noexpand\name given.}%
}
\def\@lastname{%
  \ClassError{foobar}{No \noexpand\name given.}%
}

用法:

\documentclass[...]{foobar}
...
\name{First name}{Last name}

然后\@firstname\@lastname可以使用(例如,通过类宏)。

相关内容