File Coverage

blib/lib/Symbol/Glob.pm
Criterion Covered Total %
statement 111 111 100.0
branch 42 50 84.0
condition 1 6 16.6
subroutine 18 18 100.0
pod 7 7 100.0
total 179 192 93.2


line stmt bran cond sub pod time code
1             package Symbol::Glob;
2              
3             our $VERSION = '0.03';
4              
5 7     7   167416 use warnings;
  7         15  
  7         203  
6 7     7   39 use strict;
  7         10  
  7         215  
7 7     7   36 use Carp;
  7         18  
  7         1149  
8              
9 7     7   39 use Scalar::Util qw(reftype);
  7         11  
  7         8529  
10              
11             {
12             my (%hash_of, %code_of, %array_of, %scalar_of, %io_of, %format_of, %name_of);
13              
14             my %Slot_To_Storage_Of = (
15             SCALAR => \%scalar_of,
16             ARRAY => \%array_of,
17             HASH => \%hash_of,
18             CODE => \%code_of,
19             IO => \%io_of,
20             FORMAT => \%format_of,
21             );
22              
23             my %Slot_To_Method_Of = (
24             SCALAR => 'scalar',
25             ARRAY => 'array',
26             HASH => 'hash',
27             CODE => 'sub',
28             IO => 'io',
29             FORMAT => 'format',
30             );
31              
32             my %Method_To_Slot_Of = reverse %Slot_To_Method_Of;
33              
34             sub new {
35 31     31 1 12740 my($class, $arg_ref) = @_;
36 31         60 my $self = {};
37 31         84 bless $self, $class;
38 31         81 $self->BUILD($arg_ref);
39 29         87 return $self;
40             }
41              
42             sub BUILD {
43 31     31 1 46 my ($self, $arg_ref) = @_;
44              
45 31 100       149 die "Argument to Symbol::Glob->new() must be hash reference"
46             if not ref $arg_ref eq 'HASH';
47 29         55 my $name = $arg_ref->{'name'};
48 29 50       66 die "No typeglob name supplied" unless $name;
49              
50 29         112 $name_of{$self} = $name;
51              
52             CHECK_SLOTS:
53 29         103 for my $slot (keys %Slot_To_Storage_Of) {
54 174         247 my $slot_of = $Slot_To_Storage_Of{$slot};
55 174         238 my $method = $Slot_To_Method_Of{$slot};
56              
57             # Copy out the original glob's contents if they exist.
58 174         166 my $contents;
59             {
60 7     7   42 no strict 'refs';
  7         15  
  7         4552  
  174         171  
61 174         160 $contents = *{ $name }{$slot};
  174         428  
62             }
63              
64 174 100       387 if (defined $contents) {
65 68 100       155 if ($method eq 'scalar') {
66             # We should have gotten a reference to the scalar value here.
67 29         43 $contents = $$contents;
68             # special case: undef scalar is \undef.
69 29 100       176 next CHECK_SLOTS if !defined $contents;
70             }
71              
72 51         172 $self->$method($contents);
73             }
74              
75             # Arguments supplied to new() override
76             # the glob contents.
77 157 100       477 next CHECK_SLOTS if !exists $arg_ref->{$method};
78              
79 12         20 my $override = $arg_ref->{$method};
80              
81 12 100       30 if (defined $override) {
82 7         18 $self->$method($override);
83             }
84             }
85              
86             # Object and glob are now in sync.
87 29         111 return $self;
88             }
89              
90             sub scalar {
91 18     18 1 85 my ($self, $value) = @_;
92              
93 18 100       56 if (defined $value) {
94 14         622 $self->_reslot(\$value, \%scalar_of, 'SCALAR');
95             }
96              
97 18         38 my $return_value = $scalar_of{$self};
98 18 50       589 return !defined $return_value ? undef
    50          
99             : !ref $return_value ? $return_value
100             : $$return_value;
101             }
102              
103             sub hash {
104 24     24 1 625 my ($self, $value) = @_;
105 24 100       64 if (defined $value) {
106 19 100       97 wantarray ? %{$self->_reslot($value, \%hash_of, 'HASH')}
  1         4  
107             : $self->_reslot($value, \%hash_of, 'HASH');
108             }
109             else {
110 5 100       35 wantarray ? %{$hash_of{$self}} : $hash_of{$self};
  1         7  
111             }
112             }
113              
114             sub array {
115 23     23 1 57 my ($self, $value) = @_;
116 23 100       59 if (defined $value) {
117 18 100       68 wantarray ? @{$self->_reslot($value, \%array_of, 'ARRAY')}
  1         4  
118             : $self->_reslot($value, \%array_of, 'ARRAY');
119             }
120             else {
121 5 100       71 wantarray ? @{$array_of{$self}} : $array_of{$self};
  1         6  
122             }
123             }
124              
125             sub sub {
126 17     17 1 46 my ($self, $value) = @_;
127 17 100       55 if (defined $value) {
128 13         615 $self->_reslot($value, \%code_of, 'CODE');
129             }
130             else {
131 4         21 $code_of{$self};
132             }
133             }
134              
135             sub _reslot {
136 64     64   116 my ($self, $value, $slot_of_ref, $slot_to_be_replaced) = @_;
137 64 100       158 if ($slot_to_be_replaced eq 'SCALAR') {
138 14         46 $slot_of_ref->{$self} = $$value;
139             }
140             else {
141 50         132 $slot_of_ref->{$self} = $value;
142             }
143              
144 64 0 0     253 croak "You can't fill a $slot_to_be_replaced with a " . reftype($value)
      33        
145             unless (reftype($value) eq $slot_to_be_replaced) or
146             (reftype($value) eq 'REF' and $slot_to_be_replaced eq 'SCALAR');
147              
148             # Handy way to reference the glob.
149 64         123 my $dest = $name_of{$self};
150              
151             {
152 7     7   40 no strict;
  7         11  
  7         213  
  64         67  
153 7     7   40 no warnings 'redefine';
  7         16  
  7         1381  
154 64         79 *{$dest} = $value;
  64         244  
155             }
156            
157 64         233 return $slot_of_ref->{$self};
158             }
159              
160             sub delete {
161 8     8 1 29 my ($self, $slot_to_delete) = @_;
162 8         8 my $storage_ref;
163              
164             # delete the slot in the object, and
165             # then copy the object back into the
166             # glob again as we do duing BUILD.
167 8 50       598 if (defined $slot_to_delete) {
168 8         15 my $glob_slot = $Method_To_Slot_Of{$slot_to_delete};
169 8         13 $storage_ref = $Slot_To_Storage_Of{$glob_slot};
170              
171 8         24 delete $storage_ref->{$self};
172             }
173            
174             # Delete the glob so it can be reconstituted.
175 8         18 my $dest = $name_of{$self};
176 8         56 my ($package, $symbol) = ($dest =~ /(.*::)*(.*)/);
177 8 50       22 $package = __PACKAGE__.'::' unless $package;
178 8         8 my $globref;
179              
180             {
181 7     7   36 no strict;
  7         10  
  7         856  
  8         10  
182 8         9 $globref = \%{$package};
  8         19  
183 8         11 undef *{$dest};
  8         44  
184             }
185              
186             # If no argument, deleting everything.
187 8 50       19 return unless defined $slot_to_delete;
188              
189 8         25 for my $method (keys %Method_To_Slot_Of) {
190 48 100       93 next if $method eq $slot_to_delete;
191              
192 40         57 $storage_ref = $Slot_To_Storage_Of{$Method_To_Slot_Of{$method}};
193 40         64 my $value = $storage_ref->{$self};
194 40 100       70 $value = \$value if $method eq 'scalar';
195              
196             {
197 7     7   35 no warnings 'redefine';
  7         18  
  7         245  
  40         41  
198 7     7   102 no strict 'refs';
  7         12  
  7         752  
199            
200 40 100       142 $globref->{$symbol} = $value
201             if defined $storage_ref->{$self};
202             }
203             }
204             }
205             }
206              
207             1; # Magic true value required at end of module
208             __END__