File Coverage

blib/lib/Data/Lazy.pm
Criterion Covered Total %
statement 104 134 77.6
branch 42 56 75.0
condition 2 3 66.6
subroutine 12 18 66.6
pod 1 1 100.0
total 161 212 75.9


line stmt bran cond sub pod time code
1             package Data::Lazy;
2 4     4   100156 use vars qw($VERSION);
  4         9  
  4         380  
3             $VERSION='0.6';
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 4     4   22 use Carp;
  4         8  
  4         653  
12              
13             sub LAZY_STOREVALUE () {0}
14             sub LAZY_STORECODE () {1}
15             sub LAZY_READONLY () {2}
16 0     0 1 0 sub LAZY_UNTIE () {croak "pass reference to tied var, not LAZY_UNTIE"}
17              
18 4     4   31 use strict;
  4         11  
  4         4268  
19              
20             sub TIESCALAR {
21 8     8   3317 my $pack = shift;
22 8         16 my $self = {};
23 8         21 $self->{code} = shift;
24 8 100       24 $self->{'store'} = $_[0] if $_[0];
25 8         15 $self->{'type'} = 0;
26 8         47 bless $self => $pack; # That's it? Yup!
27             }
28              
29             sub TIEARRAY {
30 3     3   780 my $pack = shift;
31 3         7 my $self = {};
32 3         8 $self->{code} = shift;
33 3 50       14 $self->{'store'} = $_[0] if $_[0];
34 3         7 $self->{'type'} = 1;
35 3         9 $self->{'size'} = 0;
36 3         15 bless $self => $pack; # That's it? Yup!
37             }
38              
39             sub FETCHSIZE {
40 3     3   2296 my $self = shift;
41 3         15 return $self->{'size'};
42             }
43              
44             sub TIEHASH {
45 1     1   839 my $pack = shift;
46 1         3 my $self = {};
47 1         3 $self->{code} = shift;
48 1 50       4 $self->{'store'} = $_[0] if $_[0];
49 1         2 $self->{'type'} = 2;
50 1         2 ${$self->{'value'}}{$;} = $self->{code};
  1         3  
51 1         5 bless $self => $pack; # That's it? Yup!
52             }
53              
54             sub FETCH {
55              
56 49     49   5512 my $self = shift;
57 49 100       161 if ($self->{'type'} == 0) {
    100          
58             # scalar
59 11 100       42 return $self->{value} if exists $self->{value};
60 8 100       22 if (ref $self->{code} eq 'CODE') {
61 7         10 $self->{value} = &{$self->{code}};
  7         21  
62             } else {
63 1         58 $self->{value} = eval $self->{code};
64             }
65 8 100       50 if (ref $self->{store}) {
66 1         2 untie(${ delete $self->{store} });
  1         4  
67             }
68 8         42 $self->{value};
69             } elsif ($self->{'type'} == 1) {
70             # array
71 34 50       93 if ($_[0] < 0) {
    100          
72 0         0 $_[0] %= $self->{'size'}
73             } elsif ($_[0] - $self->{'size'} >= 0) {
74 5         11 $self->{'size'} = $_[0]+1;
75             }
76 34 100       92 return ${$self->{'value'}}[$_[0]] if defined ${$self->{'value'}}[$_[0]];
  14         48  
  34         84  
77 20 50       50 if (ref $self->{code} eq 'CODE') {
78 20         22 ${$self->{'value'}}[$_[0]] = &{$self->{code}}(@_);
  20         57  
  20         62  
79             } else {
80 0         0 ${$self->{'value'}}[$_[0]] = eval $self->{code};
  0         0  
81             }
82 20         44 ${$self->{'value'}}[$_[0]];
  20         82  
83             } else {
84             # hash
85 4 100       5 unless (exists ${$self->{'value'}}{$_[0]}) {
  4         19  
86 3 50       9 if (ref $self->{code} eq 'CODE') {
87 3         4 ${$self->{'value'}}{$_[0]} = &{$self->{code}}(@_);
  3         17  
  3         9  
88             } else {
89 0         0 ${$self->{'value'}}{$_[0]} = eval $self->{code};
  0         0  
90             }
91             }
92 4         5 ${$self->{'value'}}{$_[0]};
  4         18  
93             }
94             }
95              
96             sub STORE {
97            
98 7     7   3694 my $self = shift;
99 7 100       31 if ($self->{'type'} == 0) {
    100          
100 5 50       17 if ($self->{'store'}) {
101              
102 5         12 delete $self->{value};
103 5 100       25 if (defined $_[0]) {
104 3 100       17 if ($self->{'store'} == LAZY_READONLY) {
    100          
105 1         218 croak "Modification of a read-only value attempted";
106             } elsif (ref $self->{store}) {
107             # LAZY_UNTIE
108 1         2 untie(${ delete $self->{store} });
  1         11  
109 1         8 return shift;
110             } else {
111             # $self->{'store'} == LAZY_STORECODE
112 1         12 $self->{code} = $_[0];
113             }
114             }
115             } else {
116 0         0 $self->{value} = $_[0];
117             }
118             } elsif ($self->{'type'} == 1) {
119 1 50       6 if ($_[0] - $self->{'size'} >= 0) {
120 1         4 $self->{'size'} = $_[0]+1;
121             }
122 1         2 ${$self->{'value'}}[$_[0]] = $_[1];
  1         7  
123             } else {
124 1 50       4 if ($_[0] eq $;) {
125 0         0 %{$self->{'value'}} = ();
  0         0  
126 0         0 $self->{'code'} = $_[1];
127 0         0 ${$self->{'value'}}{$;} = $self->{code};
  0         0  
128             } else {
129 1         2 ${$self->{'value'}}{$_[0]} = $_[1];
  1         5  
130             }
131             }
132             }
133              
134 0     0   0 sub EXISTS {1}
135              
136 0     0   0 sub DELETE {undef}
137              
138 0     0   0 sub CLEAR {%{$_[0]->{'value'}} = ()}
  0         0  
139              
140             sub FIRSTKEY {
141 0     0   0 my ($key,$val) = each %{$_[0]->{'value'}};
  0         0  
142 0 0       0 ($key,$val) = each %{$_[0]->{'value'}}if ($key eq $;);
  0         0  
143 0         0 $key
144             }
145             sub NEXTKEY {
146 0     0   0 my ($key,$val) = each %{$_[0]->{'value'}};
  0         0  
147 0 0       0 ($key,$val) = each %{$_[0]->{'value'}}if ($key eq $;);
  0         0  
148 0         0 $key
149             }
150              
151 4     4   25 no strict 'refs';
  4         13  
  4         1252  
152             sub import {
153 10     10   596 my $caller_pack = caller;
154 10         19 my $my_pack = shift;
155             # print STDERR "exporter args: (@_); caller pack: $caller_pack\n";
156             # if (@_ % 2) {
157             # croak "Argument list in `use $my_pack' must be list of pairs; aborting";
158             # }
159 10         40 while (@_) {
160 4         6 my $varname = shift;
161 4         7 my $function = shift;
162 4 100 66     40 my $store = (($_[0] and $_[0] =~ /^[012]$/)
    50          
163             ? shift
164             : ($function
165             ? LAZY_STOREVALUE
166             : LAZY_STORECODE));
167              
168 4 50       18 if ($varname =~ /^\%(.*)$/) { #<???>
    100          
169 0         0 my %fakehash;
170 0         0 tie %fakehash, $my_pack, $function, $store; #<???>
171 0         0 *{$caller_pack . '::' . $1} = \%fakehash;
  0         0  
172             } elsif ($varname =~ /^\@(.*)$/) { #<???>
173 1         2 my @fakearray;
174 1         5 tie @fakearray, $my_pack, $function, $store; #<???>
175 1         2 *{$caller_pack . '::' . $1} = \@fakearray;
  1         15  
176             } else {
177 3         4 $varname =~ s/^\$//;
178 3         3 my $fakescalar;
179 3         19 tie $fakescalar, $my_pack, $function, $store; #<???>
180 3         4 *{$caller_pack . '::' . $varname} = \$fakescalar;
  3         27  
181             }
182             }
183 10         33 @_ = ($my_pack);
184 10         3614 goto &Exporter::import;
185             }
186 4     4   21 use strict 'refs';
  4         7  
  4         144  
187              
188             1;
189              
190             __END__
191              
192             =head1 NAME
193              
194             Data::Lazy.pm - "lazy" (defered/on-demand) variables
195              
196             version 0.6
197              
198             (obsoletes and replaces Lazy.pm)
199              
200             =head1 SYNOPSIS
201              
202             # short form
203             use Data::Lazy variablename => 'code';
204             use Data::Lazy variablename => \&fun;
205             use Data::Lazy '@variablename' => \&fun;
206              
207             # to use options, you need to `use' the module first.
208             use Data::Lazy;
209             tie $variable, 'Data::Lazy', sub { ... }, LAZY_READONLY;
210              
211             # magic untie - slow on (broken) Perl 5.8.0
212             tie $variable, 'Data::Lazy' => \$variable, sub { ... };
213              
214             =head1 DESCRIPTION
215              
216             A very little module for generic on-demand computation of values in a
217             scalar, array or hash.
218              
219             It provides scalars that are "lazy", that is their value is computed
220             only when accessed, and at most once.
221              
222             =head2 Scalars
223              
224             tie $variable_often_unnecessary, 'Data::Lazy',
225             sub {a function taking a long time} [, $store_options];
226              
227             tie $var, 'Data::Lazy', 'a string containing some code' [, $store_options];
228              
229             use Data::Lazy variablename => 'code' [, $store_options];
230              
231             use Data::Lazy '$variablename' => \&function [, $store_options];
232              
233             The first time you access the variable, the code gets executed
234             and the result is saved for later as well as returned to you.
235             Next accesses will use this value without executing anything.
236              
237             You may specify what will happen if you try to reset the variable.
238             You may either change the value or the code.
239              
240             =over
241              
242             =item 1. LAZY_STOREVALUE
243              
244             In this mode - the default mode - changes to the variable are saved as
245             if the variable was not tied at all. For example;
246              
247             tie $var, 'Data::Lazy', 'sleep 1; 1';
248             # or tie $var, 'Data::Lazy', 'sleep 1; 1', LAZY_STOREVALUE;
249             $var = 'sleep 2; 2';
250             print "'$var'\n";
251              
252             will return:
253              
254             'sleep 2; 2'
255              
256             =item 2. LAZY_STORECODE
257              
258             In this mode, writes to the variable are assumed to be updating the
259             CODE that affects the value fetched, not the value of the variable.
260              
261             tie $var, 'Data::Lazy', 'sleep 1; 1', LAZY_STORECODE;
262             $var = 'sub { "4" }'
263              
264             will return
265              
266             '4'
267              
268             with no delay.
269              
270             If you tie the variable with LAZY_STORECODE option and then undefine
271             the variable (via C<undef($variable)>), only the stored value is
272             forgotten, and next time you access this variable, the code is
273             re-evaluated.
274              
275              
276             =item 3. LAZY_READONLY
277              
278             In this mode, writes to the variable raise an error message via
279             C<croak()> (see L<Carp>). That is,
280              
281             tie $var, 'Data::Lazy', 'sleep 1; 1', LAZY_READONLY;
282             $var = 'sleep 2; 2';
283             print "'$var'\n";
284              
285             Will give you an error message :
286              
287             Modification of a read-only value attempted at ...
288              
289             =item 4. LAZY_UNTIE
290              
291             In this mode, the variable is untie'd once it has been read for the
292             first time. This requires that a reference to the variable be passed
293             into the `tie' operation;
294              
295             tie $var, 'Data::Lazy', \$var, "sleep 1; 1";
296              
297             Note that LAZY_UNTIE was not specified; the reference to the variable
298             was automatically spotted in the input list.
299              
300             =back
301              
302             It's possible to create several variables in one "use Data::Lazy ..."
303             statement.
304              
305             =head2 Array
306              
307             The default tie mode for arrays makes I<individual items> subject to
308             similar behaviour as scalars.
309              
310             eg.
311              
312             tie @variable, 'Data::Lazy', sub { my $index = shift; ... };
313              
314             tie @var, 'Data::Lazy', 'my $index = shift; ...';
315              
316             use Data::Lazy '@variablename' => \&function;
317              
318             The first time you access some item of the list, the code gets
319             executed with $_[0] being the index and the result is saved for later
320             as well as returned to you. Next accesses will use this value without
321             executing anything.
322              
323             You may change the values in the array, but there is no way
324             (currently) to change the code, other than C<(tied @foo)-E<gt>{'code'}
325             = sub {...}> (which is considered cheating).
326              
327             eg.
328              
329             tie @var, 'Data::Lazy', sub {$_[0]*1.5+15};
330             print ">$var[1]<\n";
331             $var[2]=1;
332             print ">$var[2]<\n";
333              
334             tie @fib, 'Data::Lazy', sub {
335             if ($_[0] < 0) {0}
336             elsif ($_[0] == 0) {1}
337             elsif ($_[0] == 1) {1}
338             else {$fib[$_[0]-1]+$fib[$_[0]-2]}
339             };
340             print $fib[15];
341              
342             Currently it's next to imposible to change the code to be evaluated in
343             a Data::Lazy array. Any options you pass to tie() are ignored.
344             Patches welcome.
345              
346             The size of an array, as returned by evaluating it in scalar context
347             or the C<$#var> syntax, will return the highest index returned already
348             - or 0 if nothing has been read from it yet. Note that this behaviour
349             has changed from version 0.5, where 1 was returned on a fresh tied
350             array.
351              
352             =head2 Hash
353              
354             Eg.
355              
356             tie %variable, Data::Lazy, sub {a function taking a long time};
357              
358             tie %var, Data::Lazy, 'a string containing some code';
359              
360             use Data::Lazy '%variablename' => \&function;
361              
362             The first time you access some item of the hash, the code gets executed
363             with $_[0] being the key and the result is saved for later as well as
364             returned to you. Next accesses will use this value without executing
365             anything.
366              
367             If you want to get or set the code that's being evaluated for the previously
368             unknown items you will find it in $variable{$;}. If you change the code
369             all previously computed values are discarded.
370              
371             Ex.
372             tie %var, Data::Lazy, sub {reverse $_[0]};
373             print ">$var{'Hello world'}<\n";
374             $var{Jenda}='Jan Krynicky';
375             print ">$var{'Jenda'}<\n";
376             $fun = $var{$;};
377             $var{$;} = sub {$_ = $_[0];tr/a-z/A-Z/g;$_};
378             print ">$var[2]<\n";
379              
380             If you write something like
381              
382             while (($key,$value) = each %lazy_hash) {
383             print " $key = $value\n"; #
384             };
385              
386             only the previously fetched items are returned.
387             Otherwise the listing could be infinite :-)
388              
389             =head2 Internals
390              
391             If you want to access the code or value stored in the variable
392             directly you may use
393              
394             ${tied $var}{code}
395             and
396             ${tied $var}{value} # scalar $var
397             ${tied @var}{value}[$i] # array @var
398             ${tied %var}{value}{$name} # hash %var
399              
400             This way you may modify the code even for arrays and hashes, but be very
401             careful with this. Of course if you redefine the code, you'll want to
402             undef the {value}!
403              
404             There are two more internal variables:
405              
406             ${tied $var}{type}
407             0 => scalar
408             1 => array
409             2 => hash
410             ${tied $var}{store}
411             0 => LAZY_STOREVALUE
412             1 => LAZY_STORECODE
413             2 => LAZY_READONLY
414              
415             If you touch these, prepare for very strange results!
416              
417             An object-oriented interface to setting these variables would be
418             easily added (patches welcome).
419              
420             =head2 Examples
421              
422             1.
423             use Data::Lazy;
424             tie $x, 'Data::Lazy', sub{sleep 3; 3};
425             # or
426             # use Data::Lazy '$x' => sub{sleep 3; 3};
427              
428             print "1. ";
429             print "$x\n";
430             print "2. ";
431             print "$x\n";
432              
433             $x = 'sleep 10; 10';
434              
435             print "3. ";
436             print "$x\n";
437             print "4. ";
438             print "$x\n";
439              
440              
441             2. (from Win32::FileOp)
442             tie $Win32::FileOp::SHAddToRecentDocs, 'Data::Lazy', sub {
443             new Win32::API("shell32", "SHAddToRecentDocs", ['I','P'], 'I')
444             or
445             die "new Win32::API::SHAddToRecentDocs: $!\n"
446             };
447             ...
448              
449              
450             =head2 Comment
451              
452             Please note that there are single guotes around the variable names in
453             "use Data::Lazy '...' => ..." statements. The guotes are REQUIRED as soon as
454             you use any variable type characters ($, @ or %)!
455              
456             =head1 SIMILAR ALTERNATIVES TO THIS MODULE
457              
458             There are several notable alternatives to this module; if you come
459             across another, please forward mention to the author for inclusion in
460             this list.
461              
462             =over
463              
464             =item B<Memoize>
465              
466             Now a core module, this module performs similarly to the tied hash
467             variant of this module. However, it is more geared towards
468             static/global methods that already return the same value, whereas this
469             module works on a per-object basis.
470              
471             =item B<Object::Realize::Later>
472              
473             This module also provides for defered execution of code. This module
474             "expands" objects to their full state via (declared) methods, and
475             works via re-blessing objects into their new state. The principal
476             advantage of this approach is that your reference addresses do not
477             change, so existing pointers to these objects can stay as-is.
478              
479             =item B<Tie::Discovery>
480              
481             Almost identical to the hash variant of this module, the principle
482             extra feature provided by Tie::Discovery is that instead of a single
483             code reference which must supply all fetched values, individual
484             "handlers" are registered for each key for which values are wanted.
485             This makes it particularly useful for configuration files.
486              
487             =back
488              
489             =head1 BUGS
490              
491             Due to incomplete support for tie'ing arrays in very old versions of
492             Perl (ie, before 5.004), to fetch the size of an array, you cannot
493             just evaluate it in scalar context; you have to use:
494              
495             tied(@a)->{'size'}
496              
497             the usual;
498              
499             scalar(@a); # or ($#a + 1)
500              
501             will return zero! :-(
502              
503             =head2 AUTHOR
504              
505             Jan Krynicky <Jenda@Krynicky.cz>
506              
507             =head2 COPYRIGHT
508              
509             Copyright (c) 2001 Jan Krynicky <Jenda@Krynicky.cz>. All rights reserved.
510             This program is free software; you can redistribute it and/or
511             modify it under the same terms as Perl itself.
512              
513             Some changes copyright (c) 2004, Sam Vilain <samv@cpan.org>. All
514             rights reserved. Changes distributed under terms of original license.
515              
516             =cut