Data::Locations

NAME

Data::Locations - recursive placeholders in the data you generate

``Locations'' free you from the need to GENERATE data in the same order in which it will be USED later.

They allow you to define insertion points in the middle of your data which you can fill in later, at any time you want!

For instance you do not need to write output files in rigidly sequential order anymore using this module.

Instead, write the data to locations in the order which is the most appropriate and natural for you!

When you're finished, write your data to a file or process it otherwise, purely in memory (faster!).

Most important: You can nest these placeholders in any way you want!

Potential infinite recursions are detected automatically and refused.

This means that you can GENERATE data ONLY ONCE in your program and USE it MANY TIMES at different places, while the data itself is stored in memory only once.

Maybe a picture will help to better understand this concept:

Think of ``locations'' as folders (or drawers) containing papers in a sequential order, most of which contain printable text or data, while some may contain the name of another folder (or drawer).

When dumping a location to a file, the papers contained in it are printed one after another in the order they were originally stored. When a paper containing the name of another location is encountered, however, the contents of that location are processed before continuing to print the remaining papers of the current location. And so forth, in a recursive descent.

Note that you are not confined to dumping locations to a file, you can also process them directly in memory (you can read back the contents of any given location item after item or all at once)!

Note further that you may create as many locations with as many embedded locations, as many nesting levels deep as your available memory will permit.

Not even Clodsahamp's multidimensionally expanded tree house (see Alan Dean Foster's fantasy novel ``Spellsinger'' for more details!) can compare with this! :-)

See Tie and the example given at the end of this manpage for how to tie data locations to file handles in order to further simplify writing data to and reading data from locations.

See Data for even more ease of use: Use only ONE object reference instead of TWO (one for the location itself and one for the file handle the location has been tied to) which you can use as a file handle AND as a ``Data::Locations'' object reference, at the same time!

Note that this module is fully compatible with ``Data::Locations'', i.e., if you change all occurrences of ``Data::Locations'' in your program to ``Data::Locations::Shell'', your program should work exactly as before - with the added benefit that you don't need to ``tie()'' your locations to a file handle explicitly anymore in order to be able to use ``print $location @items;'' and ``$item = <$location>;'', for instance.


SYNOPSIS


TROUBLE-SHOOTING

Note that the warning messages which this module might want to issue will only appear if you use the -w switch!

Use this switch either on the command line:

                % perl -w example.pl

or append it to the ``shell-bang'' line at the top of (i.e., the very first line of) your script:

                #!/usr/local/bin/perl -w

Remember: If something strange has gone wrong with your program and you're not sure where you should look for help, try the -w switch first. It will often point out exactly where the trouble is.

Whenever you get mysterious behavior, try the -w switch!!! Whenever you don't get mysterious behavior, try using -w anyway.


DESCRIPTION


EXAMPLE #1

  #!/usr/local/bin/perl -w

  use strict;
  no strict "vars";

  use Data::Locations;

  $head = Data::Locations->new();  ##  E.g. for interface definitions
  $body = Data::Locations->new();  ##  E.g. for implementation

  $head->filename("example.h");
  $body->filename("example.c");

  $common = $head->new();    ##  Embed a new location in "$head"
  $body->print($common);     ##  Embed this same location in "$body"

  ##  Create some more locations...

  $copyright = Data::Locations->new("/dev/null");
  $includes  = Data::Locations->new("/dev/null");
  $prototype = Data::Locations->new("/dev/null");

  ##  ...and embed them in location "$common":

  $common->print($copyright,$includes,$prototype);

  ##  This is just to show you an alternate (though less efficient) way!
  ##  Normally you would use:
  ##      $copyright = $common->new();
  ##      $includes  = $common->new();
  ##      $prototype = $common->new();

  $head->println(";");  ##  The final ";" after a prototype
  $body->println();     ##  Just a newline after a function header

  $body->println("{");
  $body->println('    printf("Hello, world!\n");');
  $body->println("}");

  $includes->print("#include <");
  $library = $includes->new();     ##  Nesting even deeper still...
  $includes->println(">");

  $prototype->print("void hello(void)");

  $copyright->println("/*");
  $copyright->println("   Copyright (c) 1997 by Steffen Beyer.");
  $copyright->println("   All rights reserved.");
  $copyright->println("*/");

  $library->print("stdio.h");

  $copyright->filename("default.txt");

  $copyright->dump(">-");

  print "default filename = '", $copyright->filename(), "'\n";

  Data::Locations->dump();

  __END__

When executed, this example will print

  /*
     Copyright (c) 1997 by Steffen Beyer.
     All rights reserved.
  */
  default filename = 'default.txt'

to the screen and create the following two files:

  ::::::::::::::
  example.c
  ::::::::::::::
  /*
     Copyright (c) 1997 by Steffen Beyer.
     All rights reserved.
  */
  #include <stdio.h>
  void hello(void)
  {
      printf("Hello, world!\n");
  }

  ::::::::::::::
  example.h
  ::::::::::::::
  /*
     Copyright (c) 1997 by Steffen Beyer.
     All rights reserved.
  */
  #include <stdio.h>
  void hello(void);


EXAMPLE #2

  #!/usr/local/bin/perl -w

  use strict;
  no strict "vars";

  use Data::Locations;

  $html = Data::Locations->new("example.html");

  $html->println("<HTML>");
  $head = $html->new();
  $body = $html->new();
  $html->println("</HTML>");

  $head->println("<HEAD>");
  $tohead = $head->new();
  $head->println("</HEAD>");

  $body->println("<BODY>");
  $tobody = $body->new();
  $body->println("</BODY>");

  $tohead->print("<TITLE>");
  $title = $tohead->new();
  $tohead->println("</TITLE>");

  $tohead->print('<META NAME="description" CONTENT="');
  $description = $tohead->new();
  $tohead->println('">');

  $tohead->print('<META NAME="keywords" CONTENT="');
  $keywords = $tohead->new();
  $tohead->println('">');

  $tobody->println("<CENTER>");

  $tobody->print("<H1>");
  $tobody->print($title);      ##  re-using this location!!
  $tobody->println("</H1>");

  $contents = $tobody->new();

  $tobody->println("</CENTER>");

  $title->print("Locations Example HTML-Page");

  $description->print("Example for generating HTML pages");
  $description->print(" using 'Locations'");

  $keywords->print("Locations, magic, recursive");

  $contents->println("This page was generated using the");
  $contents->println("<P>");
  $contents->println("&quot;<B>Locations</B>&quot;");
  $contents->println("<P>");
  $contents->println("module for Perl.");

  Data::Locations->dump();

  __END__

When executed, this example will produce the following file (``example.html''):

  <HTML>
  <HEAD>
  <TITLE>Locations Example HTML-Page</TITLE>
  <META NAME="description" CONTENT="Example for generating HTML pages using 'Locations'">
  <META NAME="keywords" CONTENT="Locations, magic, recursive">
  </HEAD>
  <BODY>
  <CENTER>
  <H1>Locations Example HTML-Page</H1>
  This page was generated using the
  <P>
  &quot;<B>Locations</B>&quot;
  <P>
  module for Perl.
  </CENTER>
  </BODY>
  </HTML>


EXAMPLE #3

  #!/usr/local/bin/perl -w

  ##  WARNING: use the "-w" switch or this example won't work as described!

  package Non::Sense;  ##  works equally well with other packages than "main"!

  use strict;
  use vars qw($level0 $level1 $level2 $level3 $fh $fake);

  use FileHandle;
  use Data::Locations;

  $level0 = Data::Locations->new("level0.txt");  ##  create topmost location

  $level0->print(<<'VERBATIM');
  First line : $level0 : ->print() : (here-doc syntax)
  VERBATIM

  $level1 = $level0->new();    ##  create 1st nested location (1 level deep)

  $level0->print(<<'VERBATIM');
  Last line : $level0 : ->print() : (here-doc syntax)
  VERBATIM

  $level1->tie('STDOUT');      ##  tie this location to file handle STDOUT

  print 'First line : $level1 : print "..." : (default: STDOUT)'."\n";

  $level2 = $level1->new();    ##  create 2nd nested location (2 levels deep)

  $fh = FileHandle->new();     ##  create new file handle (IO::Handle also works)

  $level2->tie($fh);           ##  tie this location to file handle $fh

  select($fh);                 ##  select $fh as the default file handle

  print 'First line : $level2 : print "..." : (default: $fh)'."\n";

  print STDOUT 'Last line : $level1 : print STDOUT "..." : (default: $fh)'."\n";

  $level3 = $level2->new();    ##  create 3rd nested location (3 levels deep)

  select(STDOUT);              ##  re-enable STDOUT as the default file handle

  print $fh 'Last line : $level2 : print $fh "..." : (default: STDOUT)'."\n";

  $SIG{__WARN__} = sub         ##  trap all warnings
  {
      print STDERR "WARNING intercepted:\n", @_, "End Of Warning.\n";
  };

  ##  NOTE  that without this trap, warnings go to the system standard error
  ##        channel DIRECTLY, WITHOUT passing through the file handle STDERR!

  $level3->tie('STDERR');      ##  tie this location to file handle STDERR

  $fake = \$fh;

  $level3->print($fake);       ##  provoke a warning message (-w switch!)

  $level3->dump();             ##  provoke another warning message (-w switch!)

  untie *STDOUT;               ##  untie location $level1 and file handle STDOUT

  while (<STDERR>)             ##  read from location $level3
  {
      if (/^Data::Locations::/)
      {
          s/\n+//g;
          s/^.+\(\):\s*//;
          print "Warning: $_\n";
      }
  }

  while (<STDERR>) { print; }  ##  prints nothing because location wasn't reset

  ${tied *STDERR}->reset();    ##  alternative:  $level3->reset();

  while (<STDERR>) { print; }  ##  now prints contents of location $level3

  Data::Locations->dump();     ##  write output file "level0.txt"

  __END__

When running this example, the following text will be printed to the screen (provided that you used the -w switch!):

  Warning: illegal reference 'REF' ignored at test.pl line 59
  Warning: no filename given at test.pl line 61
  WARNING intercepted:
  Data::Locations::print(): illegal reference 'REF' ignored at test.pl line 59
  End Of Warning.
  WARNING intercepted:
  Data::Locations::dump_location(): no filename given at test.pl line 61
  End Of Warning.

The example also produces an output file named ``level0.txt'' with the following contents:

  First line : $level0 : ->print() : (here-doc syntax)
  First line : $level1 : print "..." : (default: STDOUT)
  First line : $level2 : print "..." : (default: $fh)
  WARNING intercepted:
  Data::Locations::print(): illegal reference 'REF' ignored at test.pl line 59
  End Of Warning.
  WARNING intercepted:
  Data::Locations::dump_location(): no filename given at test.pl line 61
  End Of Warning.
  Last line : $level2 : print $fh "..." : (default: STDOUT)
  Last line : $level1 : print STDOUT "..." : (default: $fh)
  Last line : $level0 : ->print() : (here-doc syntax)


EXAMPLE #4

The following code fragment is an example of how you can use the callback mechanism of this class to collect the contents of all top-level locations in a string (which is printed to the screen in this example):

  sub concat
  {
      $string .= $_[0];
  }

  sub list
  {
      $string .= $ruler;
      $string .= "\"" . $_[0]->filename() . "\":\n";
      $string .= $ruler;
      $_[0]->traverse(\&concat);
      $string .= "\n" unless ($string =~ /\n$/);
  }

  $ruler = '=' x 78 . "\n";

  $string = '';

  Data::Locations->traverse(\&list);

  $string .= $ruler;

  print $string;


SEE ALSO

Data::Locations::Shell(3), Tie::Handle(3), perl(1), perldata(1), perlfunc(1), perlsub(1), perlmod(1), perlref(1), perlobj(1), perlbot(1), perltoot(1), perltie(1), printf(3), sprintf(3).


VERSION

This man page documents ``Data::Locations'' version 3.0.


AUTHOR

Steffen Beyer .


COPYRIGHT

Copyright (c) 1997 by Steffen Beyer. All rights reserved.


LICENSE

This package is free software; you can redistribute and/or modify it under the same terms as Perl itself.