
Qual é a forma recomendada de definir uma variável dentro de um documento e recuperar seu valor posteriormente?
Pesquisei várias soluções diferentes no Google, geralmente com cerca de 10 linhas. Fiquei me perguntando se deve haver uma maneira mais curta de fazer algo assim (pseudocódigo):
\setvalue(VARIABLE1){foo foo bar}
e mais tarde no documento
$\getvalue(VARIABLE1)$.
Também vi soluções que incluem a definição de um novo comando, mas e se esse comando já for usado dentro de outro pacote? Isso realmente não parece uma solução independente.
Responder1
Bem, eu sei que não é o que você quer, mas a rota padrão é com a def
ou a newcommand
. O problema que você abordou é o namespace global. Se você usá-lo newcommand
, ele informará se o comando já está definido (como um erro de compilação que nomeará a newcommand
tentativa ofensiva), protegendo você desses problemas.
% Set your new variable. In this case it will be
% called "\MyNewVariable" and the value will be "hello".
\newcommand{\MyNewVariable}{hello}
% Use to get the variable.
\MyNewVariable
Se você pudesse acrescentar seu nome a todos eles ou algum outro mnemônico, é improvável que haja conflitos. Esse mnemônico então se comporta como seu próprio (espécie de) namespace.
Supondo que a primeira instância da sua variável seja definida com a newcommand
sem gerar um erro, então a renewcommand
poderá ser usado para alterar essa variável posteriormente.
Responder2
Parece que você está procurando um sistema de valores-chave. Posso sugerir pgfkeys
? Incluindo a ideia de Yiannis de usar propriedades para cada variável, eu faria assim:
\documentclass{article}
\usepackage{pgfkeys}
\newcommand{\setvalue}[1]{\pgfkeys{/variables/#1}}
\newcommand{\getvalue}[1]{\pgfkeysvalueof{/variables/#1}}
\newcommand{\declare}[1]{%
\pgfkeys{
/variables/#1.is family,
/variables/#1.unknown/.style = {\pgfkeyscurrentpath/\pgfkeyscurrentname/.initial = ##1}
}%
}
\declare{}
\begin{document}
\setvalue{VARIABLE1 = foo foo bar}
\getvalue{VARIABLE1}
\declare{test/}
\setvalue{test/property = 12}
\getvalue{test/property}
\end{document}
Menos de dez linhas, mesmo contando aquelas que possuem apenas colchetes. O funcionamento é muito simples: pgfkeys
armazena variáveis como “arquivos” em “diretórios”; Decidi que o seu deveria estar no /variables
diretório, entãonãono espaço para nome global. (A propósito, pgfkeys
as chaves nunca entram em conflito com nomes de macros normais, portanto seu "espaço para nome global" é diferente do espaço para nome de macro.)
A \setvalue
macro apenas muda o diretório apropriadamente e depois chama sua tarefa. A \getvalue
macro recupera a variável do diretório correto.
O único truque é que, em pgfkeys
, uma chave precisa ser "conhecida" antes de ser atribuída, ou então você deve chamá-la como key/.initial = value
. Como não quero forçá-lo a escrever isso, criei um "manipulador" para variáveis desconhecidas que apenas adiciona esse trecho de código nos bastidores.
Você declara uma variável com propriedades usando \declare{variable/}
e então pode usá-la variable/property
como nome de variável \setvalue
(você também pode usar variable/
como diretório padrão, então escreva
\setvalue{variable, property 1 = value 1, property 2 = value 2}
o que é conveniente). A \declare
macro apenas configura o manipulador desconhecido para o "diretório" /variables/variable/
(o que significa que a linha enigmática \declare{}
no início configura o /variables/
próprio diretório).
Responder3
Eu preferiria defini-los usando uma espécie de método Lisp ou orientado a objetos.
No mínimo abaixo, usamos:
\setproperty{test}{aproperty}{12}
\getproperty{test}{aproperty}
Pense neles como representativos test.aproperty
(na verdade os definimos como test@paproperty
), desta forma é altamente improvável que entre em conflito com quaisquer comandos existentes, exceto possivelmente o seu:
O mínimo:
\documentclass{article}
\makeatletter
% Properties a la Lisp.
\def\ece#1#2{\expandafter#1\csname#2\endcsname}%
% \setproperty{ATOM}{PROPNAME}{VALUE} defines the property PROPNAME on the
% ``atom'' ATOM to have VALUE.
%
\def\setproperty#1#2#3{\ece\protected@edef{#1@p#2}{#3}}%
\def\setpropertyglobal#1#2#3{\ece\protected@xdef{#1@p#2}{#3}}%
%
%
% \getproperty{ATOM}{PROPNAME} expands to the value of the property
% PROPNAME on ATOM, or to nothing (i.e., \empty), if the property isn't
% present.
%
\def\getproperty#1#2{%
\expandafter\ifx\csname#1@p#2\endcsname\relax
% then \empty
\else \csname#1@p#2\endcsname
\fi
}%
%
\makeatother
\begin{document}
\setproperty{test}{aproperty}{12}
\getproperty{test}{aproperty}
\end{document}
Responder4
Seu código é ConTeXt quase válido: você define uma variável usando
\setvalue{variable1}{value}
e pode obter seu valor usando
\getvalue{variable1}
(Estes são semelhantes \@namedef
e \@nameuse
no LaTeX). Se quiser variáveis baseadas em valores-chave, você pode usar:
\definenamespace
[VAR]
[
name=VAR,
setup=list,
command=list,
parent=VAR,
]
\setupVAR
[a={default A},
b={default B}]
\defineVAR
[set1]
[a={set1 A},
c={set1 C}]
\defineVAR
[set2]
[b={set2 B},
c={set2 C}]
\starttext
\startlines
\namedVARparameter{set1}{a} % gives set1 A
\namedVARparameter{set1}{b} % gives default B
\namedVARparameter{set1}{c} % gives set1 C
\stoplines
\stoptext