## LATEX-L@LISTSERV.UNI-HEIDELBERG.DE

 Options: Use Classic View Use Monospaced Font Show Text Part by Default Show All Mail Headers Topic: [<< First] [< Prev] [Next >] [Last >>]

 Collections of instances Javier Múgica de Rivera <[log in to unmask]> Sun, 22 Oct 2006 23:49:44 +0200 text/plain (215 lines) Some months ago I pointed out in another message that I wanted to make some remarks about templates. Well, we all know the pace of this list, where months play the rôle of days, so here it is: There is something about how collections work that puzzles me. Currently, if one wishes to use the instance "iname" of the type "type", one has to write \UseInstance{type}{iname}, no matter whether the instance was declared via \DeclareInstance or via \DeclareCollectionInstance. So, ¿what are the collections for? I know, to restrict the use of an instance to a particular collection. Form my point of view the existence of instances should be independent from the association of particular instances with certain collections. Thus, a file may store the declaration of a bunch of instances for a particular template, say, for a heading formating template. Supose they are called ''simple", "beautiful", "front1", "front2", where the names of the last ones suggest that they are specifically designed to be used in front matters. And suppose that for a particular work or in a particular series of books the designer decides to make use of the instance "front1" to format the headings at the frontmatter. Then he may write \AssociateInstanceCollection{heading}{frontmatter}{front1}, and at some point in the document near the beginning the author or, more likely, a macro defined by the designer, writes \UseCollection{heading}{frontmatter}, so that from now on (normal scoping rules) the instance to be used to format headings is the corresponding to the collection frontmatter. An so when the time comes to create a heading (posibly inside another macro) one simply writes \UseInstance{heading}{}, where the empty second argument means: "Use the instance that is in force for the type heading", and an error is issued if such an instance doesn't exist, i.e., if there has not been a previous call to \UseCollection where the first argument is "heading" and also a suitable call to \AssociateInstanceCollection. This allows the creation of very simple high level commands. Think for example about formating a caption. One may simply use always \UseInstance{caption}{}, and the setting of the collection in force will be made by the commands that format the particular float: figures, tables, pieces of code,... Thus, once the skeleton is written, a separate format-defining file will consist of severall calls to \AssociateInstanceCollection{type}{collection}{iname} (among other tings), setting the appearance of the documment. Furthermore, one could write \SetCollection{frontamtter} in order to set in force all the instances of all types that have been associated to the collection. I think it wouldn't be very difficult to implement this. At the present time the command that gets executed when \UseInstance is called is \type/iname, wher "coll" may be empty. We can have simply \type/iname. The definition of \AssociateInstanceCollection would then be: \def\AssociateInstanceCollection#1#2#3{ % type, collection, iname   \let:cc{#1/??_#2}{#1/#3} } Where it can be seen that ??_coll is a faked iname that gets assigned to a real iname via \AssociateInstanceCollection. The code for \UseCollection is then \def\UseCollection#1#2{ % type, collection   \let:cc{#1/???}{#1/??_#2} } And so type/??? means "current iname according to the collection in force for this type". This definition needs a check to test if \type/??_coll has been associated to a real iname, and if not issue an error or define \type/??_coll to issue an error. This last option allows the association to take place latter, since \UseCollection may appear in the definition of a macro that expects the association to be performed before the macro is called. It will also complicate the initial check for \type/??_coll, but see below. We need also, at the moment of declaring a type, to define \type/??? to issue an error. If we do not the user will get the error "the instance ??? for type heading is not defined", or something like that. The command \SetCollection executes, if it is defined, \TP_tlp_set_collection_coll (coll is #1): \def:Npn\SetCollection#1{   \cs:w TP_tlp_set_collection_#1\cs_end: } \TP_tlp_set_collection_coll will get dinamically defined by adding code to it every time we call \AssociateInstanceCollection. We have then to modify the previous definition of this macro. It may also be useful to know which instance is associated to a particular collection, if any. In particular, it is necesary for the check needed at \SetCollection:   \def:Npn\AssociateInstanceCollection#1#2#3{ % type, collection, iname   \let:cc{#1/??_#2}{#1/#3}   %Here we localy (important) add the command \UseCollection{#1}{#2} to de definition of \TP_tlp_set_collection_coll   \tlp_put_right:cn{TP_tlp_set_collection_#2}{\UseCollection{#1}{#2}}   %Record that type+collection is from now on iname:   \def:cpn{TPC>/#1/#2}{#3} %Note the order #1/#2. We always regard a collection as an indirect iname for types. } And the definition of \UseCollection will then be: \def:Npn\UseCollection#1#2{ % type, collection   \expandafter\ifx\csname TPC>/#1/#2\endcsname\relax %define #1/??_#2 to be an error message     \def:cpn{#1/??_2}{PackageError{template}{There is not defined any instance of type #1 to be used with the collection #2}}   \else     \let:cc{#1/???}{#1/??_#2}   \fi } We need also to modify slightly the definition of UseInstance to check if the second argument is empty, and if so execute \type/??? (i.e. \#1/???) instead of \type/iname (\#1/#2). It is important that the list TP_tlp_set_collection_coll (for every particular coll) be updated locally, as the collection in force is also associated locally. It works properly because \UseCollection{type}{coll} is appended to the right, so that local settings override those from an outer scope. We cannot provide a global \gAssociateInstanceCollection, since a global setting of TP_tlp_set_collection_coll will play havoc on the other types. (We can make a really ugly hack, by executing \globalhack_TP_type_coll, defined as {\tlp_put_right:cn{TP_tlp_set_collection_coll}{\UseCollection{type}{coll}}\aftergroup\globalhack_TP_type_coll}, where type and coll are parameters #1 and #2, but this does not seem the right solution). The right solution is to make TP_tlp_set_collection_coll consist of several tlp! So that TP_tlp_set_collection_front could be for example {\TP_tlp_set_collection_front_heading\TP_tlp_set_collection_front_foot\TP_tlp_set_collection_front_chapter} Each of the individual tlp's is really a stak, where inner associations get added to the left and thus override outer ones. The final definition of \AssociateInstanceCollection is then: \def:Npn\AssociateInstanceCollection#1#2#3{ % type, collection, iname   \let:cc{#1/??_#2}{#1/#3}   %The following line is pseudocode. It doesn't seem to be difficult to translate into code,   %but this is the first time I use a tlp or any of its relatives (I can't even remember which kinds of structures exsit),   %so I didn't bother to look in the manual for the functions that I need.   look if \cs:w TP_tlp_set_collection_#2_#1\end_cs: appears in \cs:w TP_tlp_set_collection_#2\end_cs: %Assume the real function is of type TF   {      \tlp_gput_right:cc{TP_tlp_set_collection_#2}{TP_tlp_set_collection_#2_#1}  %Make it global so that we insert it once and for ever     \gdef:cn{TP_tlp_set_collection_#2_#1}{}   }   {}   \tlp_put_right:cn{TP_tlp_set_collection_#2_#1}{\UseCollection{#1}{#2}}   %Record that type+collection is from now on iname:   \def:cpn{TPC>/#1/#2}{#3} %Note the order #1/#2. We always regard a collection as an indirect iname for types. } This new definition of \AssociateInstanceCollection needs TP_tlp_set_collection_coll to exist, so we may either add a check and create it if necessary, or define \DeclareCollection#1{ \tlp_new:cn{TP_tlp_set_collection_#1}{}. A global version of \AssociateInstanceCollection is now trivial: \def:Npn\AssociateInstanceCollection#1#2#3{ % type, collection, iname   \glet:cc{#1/??_#2}{#1/#3}   look if \cs:w TP_tlp_set_collection_#2_#1\end_cs: appears in \cs:w TP_tlp_set_collection_#2\end_cs: %Assume the real function is of type TF   {      \tlp_gput_right:cc{TP_tlp_set_collection_#2}{TP_tlp_set_collection_#2_#1}   }   {}   \gdef:cn{TP_tlp_set_collection_#2_#1}{\UseCollection{#1}{#2}}   \gdef:cpn{TPC>/#1/#2}{#3} } Successive calls to \AssociateInstanceCollection within the same group will keep unnecessary \UseCollection{type}{coll}, but I think it is not a problem in practice, and in order to eliminate them we should know whether the last \UseCollection{type}{coll} of TP_tlp_set_collection_coll_type comes from the current gruop or from an outer one, which seem awckward. And that's all! If all of the above is useless, do not feel sympathy whith me! I really needed to unrust myself, its a long time since I last worked with TeX. Javier A.