home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2004 December / PCpro_2004_12.ISO / files / webserver / tsw / TSW_3.4.0.exe / Apache2 / perl / Lazy.pm < prev    next >
Encoding:
Perl POD Document  |  2001-05-17  |  9.4 KB  |  389 lines

  1. package Data::Lazy;
  2. use vars qw($VERSION);
  3. $VERSION='0.5';
  4.  
  5. require Tie::Scalar;
  6. require Exporter;
  7. @ISA=qw(Exporter Tie::Scalar);
  8.  
  9. @EXPORT = qw(LAZY_STOREVALUE LAZY_STORECODE LAZY_READONLY);
  10.  
  11. sub LAZY_STOREVALUE () {0}
  12. sub LAZY_STORECODE  () {1}
  13. sub LAZY_READONLY   () {2}
  14.  
  15. use Carp;
  16. use strict;
  17.  
  18. sub TIESCALAR {
  19.   my $pack = shift;
  20.   my $self = {};
  21.   $self->{code} = shift;
  22.   $self->{'store'} = $_[0] if $_[0];
  23.   $self->{'type'} = 0;
  24.   bless $self => $pack;        # That's it?  Yup!
  25. }
  26.  
  27. sub TIEARRAY {
  28.   my $pack = shift;
  29.   my $self = {};
  30.   $self->{code} = shift;
  31.   $self->{'store'} = $_[0] if $_[0];
  32.   $self->{'type'} = 1;
  33.   $self->{'size'} = 1;
  34.   bless $self => $pack;        # That's it?  Yup!
  35. }
  36.  
  37. sub TIEHASH {
  38.   my $pack = shift;
  39.   my $self = {};
  40.   $self->{code} = shift;
  41.   $self->{'store'} = $_[0] if $_[0];
  42.   $self->{'type'} = 2;
  43.   ${$self->{'value'}}{$;} = $self->{code};
  44.   bless $self => $pack;        # That's it?  Yup!
  45. }
  46.  
  47. sub FETCH {
  48.  
  49.   my $self = shift;
  50.   if ($self->{'type'} == 0) {
  51.    return $self->{value} if exists $self->{value};
  52.    if (ref $self->{code} eq 'CODE') {
  53.          $self->{value} = &{$self->{code}};
  54.    } else {
  55.          $self->{value} = eval $self->{code};
  56.    }
  57.    $self->{value};
  58.   } elsif ($self->{'type'} == 1) {
  59.    if ($_[0] < 0) {
  60.     $_[0] %= $self->{'size'}
  61.    } elsif ($_[0] - $self->{'size'} >= 0) {
  62.     $self->{'size'} = $_[0]+1;
  63.    }
  64.    return ${$self->{'value'}}[$_[0]] if defined ${$self->{'value'}}[$_[0]];
  65.    if (ref $self->{code} eq 'CODE') {
  66.          ${$self->{'value'}}[$_[0]] = &{$self->{code}};
  67.    } else {
  68.          ${$self->{'value'}}[$_[0]] = eval $self->{code};
  69.    }
  70.    ${$self->{'value'}}[$_[0]];
  71.   } else {
  72.    return ${$self->{'value'}}{$_[0]} if defined ${$self->{'value'}}{$_[0]};
  73.    if (ref $self->{code} eq 'CODE') {
  74.          ${$self->{'value'}}{$_[0]} = &{$self->{code}};
  75.    } else {
  76.          ${$self->{'value'}}{$_[0]} = eval $self->{code};
  77.    }
  78.    ${$self->{'value'}}{$_[0]};
  79.   }
  80. }
  81.  
  82. sub STORE {
  83.     
  84.   my $self = shift;
  85.   if ($self->{'type'} == 0) {
  86.    if ($self->{'store'}) {
  87.  
  88.       delete $self->{value};
  89.       if (defined $_[0]) {
  90.        if ($self->{'store'} == LAZY_READONLY) {
  91.         croak "Modification of a read-only value attempted";
  92.        } else {
  93.         $self->{code} = $_[0];
  94.        }
  95.       }
  96.     } else {
  97.       $self->{value} = $_[0];
  98.     }
  99.   } elsif ($self->{'type'} == 1) {
  100.     ${$self->{'value'}}[$_[0]] = $_[1];
  101.   } else {
  102.     if ($_[0] eq $;) {
  103.      %{$self->{'value'}} = ();
  104.      $self->{'code'} = $_[1];
  105.      ${$self->{'value'}}{$;} = $self->{code};
  106.     } else {
  107.      ${$self->{'value'}}{$_[0]} = $_[1];
  108.     }
  109.   }
  110. }
  111.  
  112. sub EXISTS {1}
  113.  
  114. sub DELETE {undef}
  115.  
  116. sub CLEAR {%{$_[0]->{'value'}} = ()}
  117.  
  118. sub FIRSTKEY {
  119.     my ($key,$val) = each %{$_[0]->{'value'}};
  120.     ($key,$val) = each %{$_[0]->{'value'}}if ($key eq $;);
  121.     $key
  122. }
  123. sub NEXTKEY {
  124.     my ($key,$val) = each %{$_[0]->{'value'}};
  125.     ($key,$val) = each %{$_[0]->{'value'}}if ($key eq $;);
  126.     $key
  127. }
  128.  
  129. no strict 'refs';
  130. sub import {
  131.   my $caller_pack = caller;
  132.   my $my_pack = shift;
  133. #  print STDERR "exporter args: (@_); caller pack: $caller_pack\n";
  134. #  if (@_ % 2) {
  135. #    croak "Argument list in `use $my_pack' must be list of pairs; aborting";
  136. #  }
  137.   while (@_) {
  138.     my $varname = shift;
  139.     my $function = shift;
  140.     my $store = (($_[0] =~ /^[012]$/) ? shift : ($function ? LAZY_STOREVALUE : LAZY_STORECODE));
  141.  
  142.     if ($varname =~ /^\%(.*)$/) {  #<???>
  143.      my %fakehash;
  144.      tie %fakehash, $my_pack, $function, $store;          #<???>
  145.      *{$caller_pack . '::' . $1} = \%fakehash;
  146.     } elsif ($varname =~ /^\@(.*)$/) {  #<???>
  147.      my @fakearray;
  148.      tie @fakearray, $my_pack, $function, $store;          #<???>
  149.      *{$caller_pack . '::' . $1} = \@fakearray;
  150.     } else {
  151.      $varname =~ s/^\$//;
  152.      my $fakescalar;
  153.      tie $fakescalar, $my_pack, $function, $store;          #<???>
  154.      *{$caller_pack . '::' . $varname} = \$fakescalar;
  155.     }
  156.   }
  157.  @_ = ($my_pack);
  158.  goto &Exporter::import;
  159. }
  160. use strict 'refs';
  161.  
  162. 1;
  163.  
  164. =head1 NAME
  165.  
  166. Data::Lazy.pm - "lazy" variables.
  167.  
  168. version 0.5
  169.  
  170. (rem: Obsoletes Lazy.pm)
  171.  
  172. =head1 SYNOPSIS
  173.  
  174.   use Data::Lazy variablename => 'code', LAZY_READONLY ;
  175.   use Data::Lazy variablename => \&fun;
  176.   use Data::Lazy '@variablename' => \&fun;
  177.  
  178. =head1 DESCRIPTION
  179.  
  180. A very little module for simulating lazines in perl.
  181. It provides scalars that are "lazy", that is their value is
  182. computed only if necessary and at most once.
  183.  
  184. =head2 Scalars
  185.  
  186.   tie $variable_often_unnecessary, Data::Lazy,
  187.     sub {a function taking a long time} [, $store_options];
  188.  
  189.   tie $var, Data::Lazy, 'a string containing some code' [, $store_options];
  190.  
  191.   use Data::Lazy variablename => 'code' [, $store_options];
  192.  
  193.   use Data::Lazy '$variablename' => \&function [, $store_options];
  194.  
  195. The first time you access the variable, the code gets executed
  196. and the result is saved for later as well as returned to you.
  197. Next accesses will use this value without executing anything.
  198.  
  199. You may specify what will happen if you try to reset the variable.
  200. You may either change the value or the code.
  201.  
  202.  1.
  203.     tie $var, Data::Lazy, 'sleep 1; 1';
  204.     # or tie $var, Data::Lazy, 'sleep 1; 1', LAZY_STOREVALUE;
  205.     $var = 'sleep 2; 2';
  206.     print "'$var'\n";
  207.  
  208.  will return
  209.  
  210.     'sleep 2; 2'
  211.  
  212.  
  213.  2.
  214.     tie $var, Data::Lazy, 'sleep 1; 1', LAZY_STORECODE;
  215.  
  216.  will return
  217.  
  218.     '2'
  219.  
  220. after 2 seconds of waiting.
  221.  
  222.  3.
  223.     tie $var, Data::Lazy, 'sleep 1; 1', LAZY_READONLY;
  224.     $var = 'sleep 2; 2';
  225.     print "'$var'\n";
  226.  
  227.  Will give you an error message :
  228.    Modification of a read-only value attempted at ...
  229.  
  230. If you tie the variable with LAZY_STORECODE option and then
  231. undef the variable, only the stored value is forgoten and
  232. next time you access this variable, the code is reevaluated.
  233.  
  234. It's possible to create several variables in one "use Data::Lazy ..." statement.
  235.  
  236. =head2 Array
  237.  
  238.  Eg.
  239.  
  240.   tie @variable, Data::Lazy, sub {a function taking a long time};
  241.  
  242.   tie @var, Data::Lazy, 'a string containing some code';
  243.  
  244.   use Data::Lazy '@variablename' => \&function;
  245.  
  246. The first time you access some item of the list, the code gets executed
  247. with $_[0] being the index and the result is saved for later as well as
  248. returned to you. Next accesses will use this value without executing
  249. anything.
  250.  
  251. You may change the values in the array, but there is no way (currently)
  252. to change the code :-(
  253.  
  254.  Ex.
  255.     tie @var, Data::Lazy, sub {$_[0]*1.5+15};
  256.     print ">$var[1]<\n";
  257.     $var[2]=1;
  258.     print ">$var[2]<\n";
  259.  
  260.     tie @fib, Data::Lazy, sub {
  261.         if ($_[0] < 0) {0}
  262.         elsif ($_[0] == 0) {1}
  263.         elsif ($_[0] == 1) {1}
  264.         else {$fib[$_[0]-1]+$fib[$_[0]-2]}
  265.     };
  266.     print $fib[15];
  267.  
  268. Currently it's next to imposible to change the code to be evaluated
  269. in a Data::Lazy array. Any options you pass to tie() are ignored.
  270.  
  271.  Due to current suport for tieing arrays in Perl (or lack thereof)
  272.  you have to use
  273.   tied(@a)->{'size'}
  274.  to get the size of the array, if you use usual
  275.   scalar(@a)
  276.  you will get zero! :-(
  277.  
  278. =head2 Hash
  279.  
  280.  Eg.
  281.  
  282.   tie %variable, Data::Lazy, sub {a function taking a long time};
  283.  
  284.   tie %var, Data::Lazy, 'a string containing some code';
  285.  
  286.   use Data::Lazy '%variablename' => \&function;
  287.  
  288. The first time you access some item of the hash, the code gets executed
  289. with $_[0] being the key and the result is saved for later as well as
  290. returned to you. Next accesses will use this value without executing
  291. anything.
  292.  
  293. If you want to get or set the code that's being evaluated for the previously
  294. unknown items you will find it in $variable{$;}. If you change the code
  295. all previously computed values are forgotten.
  296.  
  297.  Ex.
  298.     tie %var, Data::Lazy, sub {reverse $_[0]};
  299.     print ">$var{'Hello world'}<\n";
  300.     $var{Jenda}='Jan Krynicky';
  301.     print ">$var{'Jenda'}<\n";
  302.     $fun = $var{$;};
  303.     $var{$;} = sub {$_ = $_[0];tr/a-z/A-Z/g;$_};
  304.     print ">$var[2]<\n";
  305.  
  306. ! If you write something like
  307.  
  308.   while (($key,$value) = each %lazy_hash) {
  309.    print " $key = $value\n"; #
  310.   };
  311.  
  312. only the previously fetched items are returned.
  313. Otherwise the listing would be infinite :-)
  314.  
  315. =head2 Internals
  316.  
  317. If you want to access the code or value stored in the variable directly you may use
  318.  
  319.     ${tied $var}{code}
  320.     and
  321.     ${tied $var}{value} # scalar $var
  322.     ${tied @var}{value}[$i] # array @var
  323.     ${tied %var}{value}{$name} # hash %var
  324.  
  325. This way you may modify the code even for arrays and hashes, but be very
  326. careful with this. Of course if you redefine the code, you'll want to
  327. undef the {value}!
  328.  
  329. There are two more internal variables:
  330.  
  331.     ${tied $var}{type}
  332.      0 => scalar
  333.      1 => array
  334.      2 => hash
  335.     ${tied $var}{store}
  336.      0 => LAZY_STOREVALUE
  337.      1 => LAZY_STORECODE
  338.      2 => LAZY_READONLY
  339.  
  340. If you touch these, prepare for very strange results!
  341.  
  342. =head2 Examples
  343.  
  344.  1.
  345.  use Data::Lazy;
  346.  tie $x, Data::Lazy, sub{sleep 3; 3};
  347.  # or
  348.  # use Data::Lazy '$x' => sub{sleep 3; 3};
  349.  
  350.  print "1. ";
  351.  print "$x\n";
  352.  print "2. ";
  353.  print "$x\n";
  354.  
  355.  $x = 'sleep 10; 10';
  356.  
  357.  print "3. ";
  358.  print "$x\n";
  359.  print "4. ";
  360.  print "$x\n";
  361.  
  362.  
  363.  2. (from Win32::FileOp)
  364.  tie $Win32::FileOp::SHAddToRecentDocs, Data::Lazy, sub {
  365.     new Win32::API("shell32", "SHAddToRecentDocs", ['I','P'], 'I')
  366.     or
  367.     die "new Win32::API::SHAddToRecentDocs: $!\n"
  368.  };
  369.  ...
  370.  
  371.  
  372. =head2 Comment
  373.  
  374. Please note that there are single guotes around the variable names in
  375. "use Data::Lazy '...' => ..." statements. The guotes are REQUIRED as soon as
  376. you use any variable type characters ($, @ or %)!
  377.  
  378. =head2 AUTHOR
  379.  
  380.  Jan Krynicky <Jenda@Krynicky.cz>
  381.  
  382. =head2 COPYRIGHT
  383.  
  384. Copyright (c) 2001 Jan Krynicky <Jenda@Krynicky.cz>. All rights reserved.
  385. This program is free software; you can redistribute it and/or
  386. modify it under the same terms as Perl itself.
  387.  
  388. =cut
  389.