System Macros/Key Value Assignments

From Wiki
< System Macros
Revision as of 18:22, 20 April 2012 by Marco (talk | contribs) (Change two-pass intro)
Jump to navigation Jump to search

< Prev: Comma Separated Lists | Top: System Macros | Next: User Interaction >

Assignments

Assignments are the backbone of ConTeXt. Abhorred by the concept of style file hacking, we took a considerable effort in building a parameterized system. Unfortunately there is a price to pay in terms of speed. Compared to other packages and taking the functionality of ConTeXt into account, the total size of the format file is still very acceptable. Now how are these assignments done.

Assignments can be realized with:

\doassign[label][variable=value]
\undoassign[label][variable=value]

and:

\doassignempty[label][variable=value]

These macros are a syntactic rewrite for the 'set', 'clear' and 'initialize' actions:

\def\labelvariable{value}      % \doassign
\def\labelvariable{}           % \undoassign
\doifundefined{\labelvariable}
   {\def\labelvariable{value}} % \doassignempty

Using the assignment commands directly is not our ideal of user friendly interfacing, so we take some further steps.

\getparameters [label] [...=...,...=...]

Again, the label identifies the category a variable belongs to. The second argument can be a comma separated list of assignments. Duplicates are allowed, later appearances overrule earlier ones.

\getparameters
  [demo]
  [alfa=1,
   beta=2]

is equivalent to

\def\demoalfa{1}
\def\demobeta{2}

Some explanation of the inner workings of ConTeXt is in order here to make sure the source is understandable for readers, since the actual internal usage is a bit more complex than this.

In the pre-multi-lingual (simple) stadium ConTeXt took the next approach. With these definitions (that are mainly there to conserve TeX's string space):

\def\??demo {@@demo}
\def\!!width {width}
\def\!!height {height}

calling

\getparameters
  [\??demo]
  [\!!width=one,
   \!!height=2]

lead to:

\def\@@demowidth{one}
\def\@@demoheight{2}

Because we want to be able to distinguish the !! pre-tagged user supplied variables from internal counterparts, we will introduce a slightly different tag in the multi-lingual modules. There we will use c! or v!, depending on the context.

The call will typically somewhat look like this:

\getparameters
  [\??demo]
  [\c!width=\v!one,
   \c!height=2]

In the dutch interface, this would (e.g.) expand into:

\def\@@demobreedte{een}
\def\@@demohoogte{2}

but in the english interface it would become:

\def\@@demowidth{one}
\def\@@demoheight{2}

ConTeXt continues to function, because it never uses the explicit expansion, anywhere. It always relies on the \s! and \v! definitions (remember I told you not to touch them? this is why.)

Sometimes we explicitly want variables to default to an empty string, so we welcome:

\getemptyparameters [label] [...=...,...=...]

Some ConTeXt commands take their default setups from others. All commands that are able to provide backgounds or rules around some content, for instance, default to the standard command for ruled boxes. In situations like this we can use:

\copyparameters [to-label] [from-label] [name1,name2,...]

For instance

\copyparameters
  [\??internal][\??external]
  [\c!width,\c!height]

Leads to (english version):

\def\@@internalwidth  {\@@externalwidth}
\def\@@internalheight {\@@externalheight}

A lot of ConTeXt commands take optional arguments, for instance:

\dothisorthat[alfa,beta]
\dothisorthat[first=foo,second=bar]
\dothisorthat[alfa,beta][first=foo,second=bar]

Although a combined solution is possible, we prefer a separation between argument keywords and parameter assignments. The next command takes care of propper handling of such multi-faced commands.

\doifassignmentelse {...} {then ...} {else ...}

A slightly different approach is \checkparameters, which also checks on the presence of a =, just like the previous macro.

\checkparameters[argument]

The boolean \ifparameters can be used afterwards to verify that there were assignments in the supplied argument.

Two-pass data

Two-pass data is data that is saved to an external file (the .tuc file) instead of being used directly. The reason is that the information might not be present at that point. One example is the page counter. It's possible to print the total amount of pages onto the first page. This data is saved to the .tuc file, which is read again during the second run, which typsets the correct values. This section explains how to define and retrieve such two-pass data.

Defining a data set

To store values to the .tuc the command \definedataset [myset] is used to define a container for the data.

Storing data

To store key-value pairs the command \setdataset is used.

    \setdataset [myset] [foo=foo-first,  bar=bar-first]
    \setdataset [myset] [foo=foo-second, bar=bar-second]
    \setdataset [myset] [foo=foo-third,  bar=bar-third]

Subsequent calls with the same keys to different data like in the example above does not overwrite the former values. All values are stored and enumerated. The calls above lead to the following entries in the .tuc file.

utilitydata.job.datasets.collected={
 ["myset"]={
  {
   ["bar"]="bar-first",
   ["foo"]="foo-first",
  },
  {
   ["bar"]="bar-second",
   ["foo"]="foo-second",
  },
  {
   ["bar"]="bar-third",
   ["foo"]="foo-third",
  },
 },
}

The system takes care of the name of the table not to interfere with core tables.

One can also add another parameter to address the individual values (with the same keys) from subsequent calls.

\setdataset [myset] [first]  [foo=foo-first,  bar=bar-first]
\setdataset [myset] [second] [foo=foo-second, bar=bar-second]
\setdataset [myset] [third]  [foo=foo-third,  bar=bar-third]

These calls with the additional parameter lead to the following entries in the .tuc file.

utilitydata.job.datasets.collected={
 ["myset"]={
  ["first"]={
   ["bar"]="bar-first",
   ["foo"]="foo-first",
  },
  ["second"]={
   ["bar"]="bar-second",
   ["foo"]="foo-second",
  },
  ["third"]={
   ["bar"]="bar-third",
   ["foo"]="foo-third",
  },
 },
}

If one is only interested in the last saved values, the \setdataset should be used with three argements and the second argument should stay the same. Example:

\setdataset [test] [foo] [foo=first]
\setdataset [test] [foo] [foo=second]

\setdataset [test] [bar] [bar=first]
\setdataset [test] [bar] [bar=second]
\setdataset [test] [bar] [bar=third]

Retrieving the values

The values can be retrieved with the \datasetvariable command. The first argument is the data set defined with \definedataset.

The second argument is a number if the first variant with two parameters of \setdataset was used. It's the number of the \setdataset call. If the second variant with three parameters was used, then it is the identifier given in the second argument.

And the third argument is the key which value should be retrieved.

Note: In contrast to the other mentioned commands, the arguments of \datasetvariable are delimited by braces, instead of brackets, because the actually typeset data. That's ConTeXts convention.

Complete example

\starttext

    \definedataset [myset-1]

    % two arguments ⇒ the data is accessed by number
    \setdataset    [myset-1] [foo=foo-first,  bar=bar-first]
    \setdataset    [myset-1] [foo=foo-second, bar=bar-second]

    % Outputs foo-first
    \datasetvariable{myset-1}{1}{foo}\par

    % Outputs foo-second
    \datasetvariable{myset-1}{2}{foo}\par

    % Outputs bar-first
    \datasetvariable{myset-1}{1}{bar}\par

    % Outputs bar-second
    \datasetvariable{myset-1}{2}{bar}\blank


    \definedataset [myset-2]

    % three arguments ⇒ the data is accessed by identifier
    \setdataset    [myset-2] [first]  [alpha=alpha-first,  beta=beta-first]
    \setdataset    [myset-2] [second] [alpha=alpha-second, beta=beta-second]

    % Outputs alpha-first
    \datasetvariable{myset-2}{first} {alpha}\par

    % Outputs alpha-second
    \datasetvariable{myset-2}{second}{alpha}\par

    % Outputs beta-first
    \datasetvariable{myset-2}{first} {beta}\par

    % Outputs beta-second
    \datasetvariable{myset-2}{second}{beta}\par

\stoptext


< Prev: Comma Separated Lists | Top: System Macros | Next: User Interaction >