[Tex/LaTex] Define variable without \newcommand

variable

I'm writing an invoice class and I want to keep the actual tex file as clean as possible, so that the code does not scare off the non-techies.

My ultimative goal would be to define a variable in the invoice.cls file and later set a value to it by a very simple and clean command in the main.tex. Something like \address{Street, Number}{ZIP Code Town}{Country} and \name{First name}{Last name} and \bankDetails{IBAN number}{Bank Swift Code}

Keep in mind, that I have to use the values of these variables in the invoice.cls file.

At the moment I defined a newcommand in the class file and gave it some optional arguments. By calling the command and passing the arguments I had a code like the one above. The thing is, that I need to access the name variable at multiple places and I don't want that the end user has to enter his name several times as arguments… It would be nice to define these variables globally and access them whenever I need them.

Like with

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

But you'll understand that

\name{John}{Doe}

would be much cleaner.

Best Answer

I am a great fan of expl3 and its property 'variable' feature, i.e. a key - based storage of data. As long as the amount of keys is not too large prop lists are very convenient.

A key might be FirstName or Zip.

The macro \StoreInvoiceData stores the keys given as FirstName=foo, IBAN=US345342342 etc into the relevant key slot of the property list, named \g_sam_invoice_prop here. The key-value-interface of the macro must not be confused with the keys of the property list, although the storage mechanism in the background is identical. The key= name is the same as the property key name, this is not mandatory but convenient in order to remember the names.

The order of specification does not matter at all.

Use \GetInvoiceData{foo} for example in order to extract the value of the foo key.

\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}

enter image description here

Version for checking whether a key is given

\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}

enter image description here

Related Question