I am writing a templat/class for a club that should be used for official protocols of meetings.

Therefor we need a table of attendees at the beginning of the protocol and at the point where the person left, we need the time the person left (or joined or came back).

I want to define 3 commands \maketableofattendees, \joins[time]{Name}, \leaves[time]{Name}.

The table of attendees should show the list of all attendees that joined with the first time they joined and the last time they left.

also should the joins and leaves be printed in the place in the protocol where the corresponding action happened (e.g. where the joins or leaves command happens).

How can I implement this?

Edit:

Example Input:

\maketableofattendees{Attendees}
\joins[20:00]{Bob}

\section{First Topic}
First Poll: \attendeecount People Present. Yes: 2, No: 0

\joins[20:15]{Charlie}

\section{Second Topic}
Bob speaks about the second topic.
Second Poll: \attendeecount People Present. Yes: 1, No :2
\leaves[20:30]{Bob}

\section{Third Topic}
Second Poll: \attendeecount People Present. Yes: 1, No :1


this would produce something like:

Attendees:
Bob (From 20:00 to 20:30)
Charlie (From 20:15 to end)

#First Topic
First Poll: 2 People Present. Yes: 2, No: 0

== 20:15 Charlie enters the Meeting

# Second Topic
Bob speaks about the second topic.
Second Poll: 3 People Present. Yes: 1, No :2

== 20:30 Bob leaves the meeting

# Third Topic
Second Poll: 2 People Present. Yes: 1, No :1

• Welcome to TeX.SX! Can you please show an approximate representation of the expected output? – egreg Feb 2 at 20:30
• The table of contents extracts the number, title and page number from calls to \chapter etc. From where do you intend to extract the information needed? – John Kormylo Feb 2 at 21:42
• @egreg I added an example – Tobi Feb 3 at 1:36
• You might be able to implement it as a glossary (glossary package). – John Kormylo Feb 3 at 19:32

It is possible to achieve that using the rdfref package. It is not available on CTAN, so it needs to be installed manually to the \$TEXMFHOME/tex/latex/rdfref directory.

I would modify your TeX file a bit:

\documentclass{article}
\usepackage{attendees}
\begin{document}

\maketableofattendees{Attendees}
\maketableofpolls{Polls}

\joins[20:00]{Bob}

\topic{First Topic}

\poll{First Poll}{2}{0}
% First Poll: \attendeecount People Present. Yes: 2, No: 0

\joins[20:15]{Charlie}

\topic{Second Topic}
Bob speaks about the second topic.

\poll{Second Poll}{1}{2}%: \attendeecount People Present. Yes: 1, No :2
\leaves[20:30]{Bob}

\topic{Third Topic}

\poll{Third Poll}{1}{1}%: \attendeecount People Present. Yes: 1, No :1

\end{document}


It uses an attendees custom package, it contains definitions for commands used in the document. I've added some new commands, namely \maketableofpolls which lists the used polls and topics, \topic which is used instead of the \section, and \poll which records poll name, votes and prints them.

Here is the attendees.sty package:

\ProvidesPackage{attendees}
\RequirePackage{rdfref-user,rdfref-query}

\newcommand\maketableofpolls[1]{%
\section*{#1}%
\Bind{?topic}{rdf:type}{at:topic}{%
\noindent\textbf{\GetValProperty{?topic}{at:topicName}}\dotfill\GetValProperty{?topic}{doc:pageNo}\par
\Bind{?poll}{at:pollTopic}{?topic}{%
\noindent \quad\GetValProperty{?poll}{at:pollName}. Yes: \GetValProperty{?poll}{at:pollYes}, no: \GetValProperty{?poll}{at:pollNo}\dotfill\GetValProperty{?poll}{doc:pageNo}\par
}
}
}

% \newcommand\at@printpoll

\newcommand\maketableofattendees[1]{%
\section*{#1}%
\Bind{?name}{rdf:type}{at:attendee}{%
% \GetVal prints the variable name, \GetValProperty extracts property from the name
% Set the default left time
\def\at@left{end}%
% use the real at:left if it has been set
\IfProperty{\GetVal{?name}}{at:left}{\def\at@left{\GetValProperty{?name}{at:left}}}{}%
\at@printname{\GetValProperty{?name}{at:name}}{\GetValProperty{?name}{at:joined}}{\at@left}%
}%
}

\newcommand\at@printname[3]{\noindent\textbf{#1}~(From #2 to #3)\par}

\newcommand\topic[1]{%
\section{#1}%
\BlankNode%
\edef\CurrentTopic{\CurrentObject}% we want to reference the current topic in the poll
}
\newcommand\joins[2][]{%
\WithObject{#2}{%
}%
}

\newcommand\leaves[2][]{%
\WithObject{#2}{%
\AddProperty{is:active}{} % remove the is:active property, so it doesn't pollute next \poll
}%
}

\newcounter{poll@count}
\newcommand\poll[3]{%
\setcounter{poll@count}{0}%
\BlankNode%
% process all attendands%
\Bind{?name}{rdf:type}{at:attendee}{%%
% execute the code only on active attendands
\IfProperty{\GetVal{?name}}{is:active}{\stepcounter{poll@count}}{}
}%
\par
\medskip%
\noindent\textbf{#1}: \arabic{poll@count} People Present. Yes: #2, No: #3\par
}%

\AtBeginDocument{%
% reset attendands
\Bind{?name}{rdf:type}{at:attendee}{\SetProperty{\GetVal{?name}}{is:active}{}}
}

\endinput


Quite a lot of stuff happens here. rdfref provides commands that can set properties to objects. These properties are saved to the aux file, so they are available from the beginning of the document in the next compilation. This means that the document needs two compilations each time an object changes!

There are two types of objects, named and anonymous. In our example, named objects are people that can join and leave the meeting. The following command:

\newcommand\leaves[2][]{%
\WithObject{#2}{%
\SetProperty{#2}{is:active}{} % remove the is:active property, so it doesn't pollute next \poll
}%
}


will set the time person left and makes the person inactive, so it doesn't count in the next poll. The \WithObject command sets the person name as a current object identifier and properties are saved to this object.

Two commands for property handling are used. The first one is \AddProperty, it sets a property of a current object and saves it to the aux file, which means that this property will be restored next time the document is compiled and it will be available from the beginning. It enables us to make a list of attendands and list of polls, for example. Other kind of properties is just temporary, like in this case, where we just need to disable this person in the next poll count. We can use the \SetProperty command. It needs an explicit object identifier as the first parameter.

In contrast, each poll creates anonymous object:

\newcommand\poll[3]{%
\setcounter{poll@count}{0}%
\BlankNode%
...


The \BlankNode creates an anonymous object and subsequent \AddProperty commands set properties for that. \AddPropertyEx can be used to save the expanded value of a macro, such as the page number as in our case.

The properties can be queried using the \Bind command:

\newcommand\maketableofpolls[1]{%
\section*{#1}%
\Bind{?topic}{rdf:type}{at:topic}{%
\noindent\textbf{\GetValProperty{?topic}{at:topicName}}\dotfill\GetValProperty{?topic}{doc:pageNo}\par
\Bind{?poll}{at:pollTopic}{?topic}{%
\noindent \quad\GetValProperty{?poll}{at:pollName}. Yes: \GetValProperty{?poll}{at:pollYes}, no: \GetValProperty{?poll}{at:pollNo}\dotfill\GetValProperty{?poll}{doc:pageNo}\par
}
}
}


It takes four parameters. The first three are the query and the last one is code that is executed on matched properties. In this case, we are first looking for all topics. For each object, we set rdf:type property, at:topic for topics, at:poll for polls and at:attendee for attendees. So we need to search for all objects with rdf:type set to at:topic:

  \Bind{?topic}{rdf:type}{at:topic}{%


The ?topic parameter is a variable that will contain the topic object identifier in the executed code in the fourth parameter. Here we can get various parameters of the object using the \GetValProperty command:

    \noindent\textbf{\GetValProperty{?topic}{at:topicName}}\dotfill\GetValProperty{?topic}{doc:pageNo}\par


In this case he topic name and the page number where it starts are used.

\Bind commands can be nested. To get all polls for a topic, we can use the following command which is nested in the previous \Bind:

    \Bind{?poll}{at:pollTopic}{?topic}{%


Here two variables are used. The ?topic is set from the parent bind, so it contains the current topic object. So only ?poll is searched in this command.

Another use of \Bind in in the \poll command, where it is used for counting of the current number of attendees:

 \Bind{?name}{rdf:type}{at:attendee}{%%
% execute the code only on active attendands
\IfProperty{\GetVal{?name}}{is:active}{\stepcounter{poll@count}}{}
}%


The \IfProperty command tests if object has a property. \GetVal gets the object identifier from the bind variable.

Because all properties are set to the auxilary file, they have the same values as at the end of the document. It is thus necessary to set all attendees as inactive at the document start and enable them only in the \join command:

\AtBeginDocument{%
% reset attendands
\Bind{?name}{rdf:type}{at:attendee}{\SetProperty{\GetVal{?name}}{is:active}{}}
}


The \SetProperty directly sets the property to an object. If the value is empty, it removes the property.

This is the result:

• Does it have to be in a package or can I make this part of my single class file. The reason: I want to provide one drop in file for our users that do not need a lot of fiddling around. I'd also prefer using standard packages only if possible. – Tobi Feb 3 at 16:43
• I think you can include this package and all needed files from Rdfref (rdfref-core.sty, rdfref-user.sty and rdfref-query.sty) in a class file. It would just be a bit harder to manage. – michal.h21 Feb 3 at 16:47
• Can the rdfref package be put on CTAN? – Peter Wilson Feb 3 at 18:37
• @PeterWilson it is still missing the documentation, I really should create one and put it on CTaN. – michal.h21 Feb 3 at 19:11
• can I overwrite existing at:left values? and avoid overwriting at:joined values for the attendeelist? (e.g. if someone went to the toilet and therefore wasnt there for a single poll but still should be shown on the attendeeslist from the first time they entered till the last time they left?) – Tobi Feb 3 at 22:53