THE OLD rr.pm API CHANGED

Since version 2.06 the rr.pm module in this package has one of its old
design flaws fixed through a change in the API.

CONTENTS OF THIS FILE:

 - THE PROBLEM
 - THE SOLUTION: API CHANGE
    -- NEW %::HashT VALUES
    -- SPECIAL %::HashT ELEMENTS
 - THE COMPATIBILITY ISSUES
    -- MORE COMPATIBILITY?

* THE PROBLEM

The problem is supplying values of repeatable attributes (of ReDIF
templates) to a user application.  In old rr.pm this problem had
practically no solution.  If an attribute 'x' was reapeated twice in a
template, e.g.

x: aaa
x: bbb

then the application received value "aaa; bbb" in $::HashT{x}. This
means that mulitple attribute values were concatenated by "; " sequence
into one string.

It would not be a big problem if the ReDIF values would only be used
for textual display, but even for converting ReDIF to HTML it is
already a problem.  Consider for example, the 'homepage' attribute of
'archive' templates.  When rendering an archive template as HTML, it
makes sense to present 'homepage' value as a hypertext link. But if
the 'homepage' attribute has appeared twice in a template (which is
not particularily likely but still is valid ReDIF), then two URLs will
be concatenated by a semicolon and a space ("; ") into a single value.
If the application does not check for this case, the generated link to
the archive homepage will be broken.

The real understanding of the bad consequences of this problem came to
us only in 1999 with Markus Klink raising the awareness.  But untill
recently there were no other solution to the problem. 


* THE SOLUTION: API CHANGE

There was a discussion between Thomas Krichel and me (IKu) and (a bit
later) in a wider company of Markus Klink, Sune Karlson, Jose-Manuel
Barrueco Cruz and Christian Zimmermann on how to solve the problem.

The decision was to change the structure of %::HashT hash, which
contains the template data as processed by the rr.pm module.

Usually the %::HashT variable after a &rr::NextTemplate() function
call contains a hash of attributes and values. For instance, 

   $t = $::HashT{title} ;

will put value of the 'title' attribute of a template into the $t
variable.  Some of the keys of this hash do not represent a single
attribute but instead they represent clusters of attributes.  But as
far as clusters in ReDIF data are often repeated
(e.g. Author-(*Person) cluster using the ReDIF documentation
notation), we say that some of the %::HashT keys represent arrays of
cluster hashes.  This means in particular that

   $a = $::HashT{author};

would yeild a reference to an array into $a.  That array will contain
the person clusters of the author(s).  Therefore, $a->[0] will give
you cluster of data of the first author, and $a->[1] will give you
the same of the second author (if such is present).


** NEW %::HashT VALUES

To make processing of the repeatable attributes' values correct and
explicit we decided to represent every attribute (of a ReDIF template
and its clusters) as an array of values.  So with a fix rr.pm module
will create $::HashT in such way that:

   $_t = $::HashT{title};

will put array reference into $_t variable; the array will contain
actual data.  I.e. expression $_t->[0] will return the actual value of
the 'title' attribute.  So

   $t = $::HashT{title} -> [0];   ### '->' in Perl is optional (here)

will put the actual title value into the $t variable.  So far you can
see that now representation of simple attributes in $::HashT becomes
similar to the way cluster-attributes are represented.  If an
'abstract' attribute is repeated twice in a template and if this is
valid for its template-type, then the first value will be accessible
 as  $::HashT{abstract}[0] and the second value will be accessible as
$::HashT{abstract}[1]. 

The same transformation happened to the attribute values inside
clusters.  So if you what to get a list of authors of a document and
then display their names, the following code will show how you can do that:

   my $authors_list = $::HashT{author};
   print "Author(s): ";
   foreach my $author ( @$authors_list ) {
       print $author->{name}[0];    ###  note '[0]' here 
   }
 
That's it.  No other changes happened.  But to clarify once again, all
attributes independently of their repeatability status or other
curcumstanses are now always represented as arrays of values.


** SPECIAL %::HashT ELEMENTS

The change of API in no way changes the values of special upper-case
%::HashT keys, such as 'FILENAME', 'STARTFPOS' and so on.


* THE COMPATIBILITY ISSUES

The rr.pm software plays important role in RePEc system, because
(almost) all other software relies on rr.pm to read ReDIF data. 

The above-described API change makes old rr.pm incompatible with
the new rr.pm.  Such change would be very dangerous in our distributed
environment.  Therefore special measures to limit the incompatibility
effects are taken.  In particular,

THE EXISTING RePEc PROGRAMS WILL CONTINUE TO WORK EXACTLY AS THEY DID
BEFORE WITH THE NEW VERSION OF rr.pm MODULE INSTALLED.

The updated API will only work if the application exploiting rr.pm
will request it.  So the default behaviour of rr.pm will not change.
To make use of the new API, the application has to set a special
variable before use-ing the rr.pm module.  This will be explained in
detail in this section.

The traditional way to use the rr.pm module in a Perl program is to
include 'use' directive into your code.  E.g., 

#!/usr/bin/perl

   use rr;

It is also possible that you woud like to import some rr.pm routines
into your package by saying something like

   use rr qw( OpenRDF NextTemplate );

To get the fixed behaviour of rr.pm you'd have to change that line in
the following way.  You must add 'BUG_FIX' to the list of parameters
of the 'use' statement:

   use rr qw( BUG_FIX );            ### this will not import any symbols 

or 

   use rr BUG_FIX;                  ### this will not import any symbols 

or

   use rr qw( BUG_FIX OpenRDF NextTemplate );  ### will import the functions

All these variations shall work.  This mechanizm will also provide
your application a trap for a situation when an updated programm is
executed on a machine with old rr.pm.  Versions of rr.pm before 2.06
will cause a crash if string 'BUG_FIX' will apear at the 'use'
statement.   

If you want you may trap the crash, caused by an older rr.pm in a new
(updated) application.  Consider the following code instead of a
simple "use rr ..." statement:

   BEGIN {
       eval 'use rr BUG_FIX;'  ;  ###  add functions names here if needed
       if ( $@ ) {
           if ( $@ =~ /import errors/ ) {   
	       die "Please install a new version of rr.pm (2.06 or higher)."; 
           } else {             
       	       die $@;  ### some other error happened
           }
        }
   }


Here I assume that once updated to this API change, the applications
will not support older %::HashT format and therefore they will require
a new version of rr.pm to be installed.


** MORE COMPATIBILITY?

But if you need/want to make your application compatible with both new
and old version of rr.pm software, you can.  Its fully a matter of
your code being able to treat %::HashT values this or that way at the
same time.  But to make sure that old rr.pm module does not crash when
you enable the new API by 'BUG_FIX' in 'use' line, you can enable the
fix in a different way.  This code

   BEGIN { $::RR_BUG_FIX = 1; }
   use rr;      

will do the trick, but note that the BEGIN block must go before "use
rr" line.  The API-fix will be enabled if the rr.pm at this site is of
2.06 version or higher.




For more information about rr.pm usage see

   http://netec.mcc.ac.uk/RePEc/rr_pm.html

or the same document in doc/ directory of this package.


Comments and corrections are welcome.


Cheers!


Ivan Kurmanov
  ivan@tm.minsk.by
  iku@fnmail.com

27th of June, 2000
+ a minor revision on 09, August, 2000
