File Coverage

blib/lib/Tie/Indirect.pm
Criterion Covered Total %
statement 55 71 77.4
branch 6 12 50.0
condition n/a
subroutine 21 32 65.6
pod n/a
total 82 115 71.3


line stmt bran cond sub pod time code
1             # License: Public Domain or CC0
2             # See https://creativecommons.org/publicdomain/zero/1.0/
3             # The author, Jim Avera (jim.avera at gmail) has waived all copyright and
4             # related or neighboring rights. Attribution is requested but is not required.
5             # $Id: Indirect.pm,v 1.9 2021/12/22 20:35:22 jima Exp jima $
6              
7             =pod
8              
9             =head1 NAME
10              
11             Tie::Indirect::* -- tie variables to access data located at run-time.
12              
13             =head1 DESCRIPTION
14              
15             Each tied variable accesses data located by calling a sub
16             which returns a reference to the data.
17            
18             The sub is called with parameters ($mutating, optional tie args...)
19             where $mutating is true if the access may modify the value.
20            
21             tie $scalar, 'Tie::Indirect::Scalar', \&sub, optional tie args...
22             tie @array, 'Tie::Indirect::Array', \&sub, optional tie args...
23             tie %hash, 'Tie::Indirect::Hash', \&sub, optional tie args...
24            
25             EXAMPLE:
26             my $dataset1 = { foo=>123, table=>{...something...}, list=>[...] };
27             my $dataset2 = { foo=>456, table=>{...something else...}, list=>[...] };
28            
29             my $masterref;
30            
31             our ($foo, %table, @list);
32             tie $foo, 'Tie::Indirect::Scalar', sub{ \$masterref->{$_[1]} }, 'foo';
33             tie %table, 'Tie::Indirect::Hash', sub{ $masterref->{$_[1]} }, 'table;
34             tie @list, 'Tie::Indirect::Array', sub{ $masterref->{list} };
35            
36             $masterref = $dataset1;
37             ... $foo, %table, and @list now access members of $dataset1
38             $masterref = $dataset2;
39             ... $foo, %table, and @list now access members of $dataset2
40            
41             =head1 AUTHOR / LICENSE
42              
43             Jim Avera (jim.avera AT gmail) / Public Domain or CC0
44              
45             =cut
46              
47             #---------------------------------------------------------------------#
48             package Tie::Indirect; # just so Dist::Zilla can add $VERSION
49             $Tie::Indirect::VERSION = '0.001';
50              
51             package
52             Tie::Indirect::Scalar;
53 1     1   561 use Carp;
  1         3  
  1         267  
54              
55             sub TIESCALAR {
56 1     1   47 my ($class, $subref, @extras) = @_;
57 1 50       6 croak "not a code ref" unless ref($subref) eq 'CODE';
58 1         4 return bless [$subref, @extras], $class
59             }
60             sub _getref {
61 11     11   29 my ($self, $mutating) = @_;
62 11         34 return $self->[0]->($mutating, @{$self}[1..$#$self]);
  11         41  
63             }
64 9     9   31127 sub FETCH { ${ $_[0]->_getref() } }
  9         26  
65 2     2   602 sub STORE { ${ $_[0]->_getref(1) } = $_[1] }
  2         8  
66              
67             ## Ignore death of the helper sub called from DESTROY
68             #sub DESTROY { eval { undef ${ $_[0]->_getref(1) } }; }
69              
70             #---------------------------------------------------------------------#
71             package
72             Tie::Indirect::Array;
73 1     1   8 use Carp;
  1         2  
  1         598  
74              
75             sub TIEARRAY {
76 1     1   9 my ($class, $subref, @extras) = @_;
77 1 50       4 croak "not a code ref" unless ref($subref) eq 'CODE';
78 1         4 return bless [$subref, @extras], $class
79             }
80             sub _getref {
81 41     41   80 my ($self, $mutating) = @_;
82 41         78 return $self->[0]->($mutating, @{$self}[1..$#$self]);
  41         117  
83             }
84             # based on code in Tie::StdArray
85 9     9   10897 sub FETCHSIZE { scalar @{$_[0]->_getref()} }
  9         25  
86 0     0   0 sub STORESIZE { $#{$_[0]->_getref(1)} = $_[1]-1 }
  0         0  
87 1     1   273 sub STORE { $_[0]->_getref(1)->[$_[1]] = $_[2] }
88 30     30   1785 sub FETCH { $_[0]->_getref()->[$_[1]] }
89 0     0   0 sub CLEAR { @{$_[0]->_getref(1)} = () }
  0         0  
90 0     0   0 sub POP { pop(@{$_[0]->_getref(1)}) }
  0         0  
91 0     0   0 sub PUSH { my $o = shift->_getref(1); push(@$o,@_) }
  0         0  
92 0     0   0 sub SHIFT { shift(@{$_[0]->_getref(1)}) }
  0         0  
93 0     0   0 sub UNSHIFT { my $o = shift->_getref(1); unshift(@$o,@_) }
  0         0  
94 0     0   0 sub EXISTS { exists $_[0]->_getref()->[$_[1]] }
95 0     0   0 sub DELETE { delete $_[0]->_getref(1)->[$_[1]] }
96             sub SPLICE
97             {
98 1     1   321 my $ob = shift;
99 1         9 my $sz = $ob->FETCHSIZE;
100 1 50       8 my $off = @_ ? shift : 0;
101 1 50       10 $off += $sz if $off < 0;
102 1 50       4 my $len = @_ ? shift : $sz-$off;
103 1         2 return splice(@{$ob->_getref(1)},$off,$len,@_);
  1         3  
104             }
105       0     sub EXTEND { }
106              
107             #---------------------------------------------------------------------#
108             package
109             Tie::Indirect::Hash;
110             require Tie::Hash;
111 1     1   7 use Carp;
  1         2  
  1         405  
112              
113             sub TIEHASH {
114 1     1   8 my ($class, $subref, @extras) = @_;
115 1 50       3 croak "not a code ref" unless ref($subref) eq 'CODE';
116 1         3 return bless [$subref, @extras], $class
117             }
118             sub _getref {
119 39     39   71 my ($self, $mutating) = @_;
120 39         92 return $self->[0]->($mutating, @{$self}[1..$#$self]);
  39         94  
121             }
122             # based on code in Tie::StdHash
123 3     3   23 sub STORE { $_[0]->_getref(1)->{$_[1]} = $_[2] }
124 15     15   1627 sub FETCH { $_[0]->_getref()->{$_[1]} }
125 5     5   4575 sub FIRSTKEY { my $o = $_[0]->_getref(); my $a = scalar keys %{$o}; each %{$o} }
  5         28  
  5         15  
  5         13  
  5         37  
126 10     10   35 sub NEXTKEY { each %{$_[0]->_getref()} }
  10         26  
127 0     0   0 sub EXISTS { exists $_[0]->_getref()->{$_[1]} }
128 0     0   0 sub DELETE { delete $_[0]->_getref(1)->{$_[1]} }
129 2     2   320 sub CLEAR { %{$_[0]->_getref(1)} = () }
  2         7  
130 4     4   292 sub SCALAR { scalar %{$_[0]->_getref()} }
  4         9  
131              
132             1;