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.04';
4              
5 7     7   501355 use warnings;
  7         106  
  7         244  
6 7     7   37 use strict;
  7         13  
  7         151  
7 7     7   32 use Carp;
  7         20  
  7         446  
8              
9 7     7   43 use Scalar::Util qw(reftype);
  7         12  
  7         1999  
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 10053 my($class, $arg_ref) = @_;
36 31         60 my $self = {};
37 31         66 bless $self, $class;
38 31         92 $self->BUILD($arg_ref);
39 29         97 return $self;
40             }
41              
42             sub BUILD {
43 31     31 1 53 my ($self, $arg_ref) = @_;
44              
45 31 100       125 die "Argument to Symbol::Glob->new() must be hash reference"
46             if not ref $arg_ref eq 'HASH';
47 29         52 my $name = $arg_ref->{'name'};
48 29 50       62 die "No typeglob name supplied" unless $name;
49              
50 29         88 $name_of{$self} = $name;
51              
52             CHECK_SLOTS:
53 29         97 for my $slot (keys %Slot_To_Storage_Of) {
54 174         253 my $slot_of = $Slot_To_Storage_Of{$slot};
55 174         240 my $method = $Slot_To_Method_Of{$slot};
56              
57             # Copy out the original glob's contents if they exist.
58 174         199 my $contents;
59             {
60 7     7   64 no strict 'refs';
  7         17  
  7         4035  
  174         215  
61 174         194 $contents = *{ $name }{$slot};
  174         356  
62             }
63              
64 174 100       319 if (defined $contents) {
65 68 100       136 if ($method eq 'scalar') {
66             # We should have gotten a reference to the scalar value here.
67 29         48 $contents = $$contents;
68             # special case: undef scalar is \undef.
69 29 100       80 next CHECK_SLOTS if !defined $contents;
70             }
71              
72 51         134 $self->$method($contents);
73             }
74              
75             # Arguments supplied to new() override
76             # the glob contents.
77 157 100       368 next CHECK_SLOTS if !exists $arg_ref->{$method};
78              
79 12         20 my $override = $arg_ref->{$method};
80              
81 12 100       26 if (defined $override) {
82 7         18 $self->$method($override);
83             }
84             }
85              
86             # Object and glob are now in sync.
87 29         53 return $self;
88             }
89              
90             sub scalar {
91 18     18 1 50 my ($self, $value) = @_;
92              
93 18 100       48 if (defined $value) {
94 14         39 $self->_reslot(\$value, \%scalar_of, 'SCALAR');
95             }
96              
97 18         36 my $return_value = $scalar_of{$self};
98 18 50       76 return !defined $return_value ? undef
    50          
99             : !ref $return_value ? $return_value
100             : $$return_value;
101             }
102              
103             sub hash {
104 24     24 1 80 my ($self, $value) = @_;
105 24 100       54 if (defined $value) {
106 19 100       73 wantarray ? %{$self->_reslot($value, \%hash_of, 'HASH')}
  1         4  
107             : $self->_reslot($value, \%hash_of, 'HASH');
108             }
109             else {
110 5 100       43 wantarray ? %{$hash_of{$self}} : $hash_of{$self};
  1         7  
111             }
112             }
113              
114             sub array {
115 23     23 1 65 my ($self, $value) = @_;
116 23 100       52 if (defined $value) {
117 18 100       56 wantarray ? @{$self->_reslot($value, \%array_of, 'ARRAY')}
  1         4  
118             : $self->_reslot($value, \%array_of, 'ARRAY');
119             }
120             else {
121 5 100       30 wantarray ? @{$array_of{$self}} : $array_of{$self};
  1         4  
122             }
123             }
124              
125             sub sub {
126 17     17 1 53 my ($self, $value) = @_;
127 17 100       37 if (defined $value) {
128 13         55 $self->_reslot($value, \%code_of, 'CODE');
129             }
130             else {
131 4         24 $code_of{$self};
132             }
133             }
134              
135             sub _reslot {
136 64     64   174 my ($self, $value, $slot_of_ref, $slot_to_be_replaced) = @_;
137 64 100       125 if ($slot_to_be_replaced eq 'SCALAR') {
138 14         50 $slot_of_ref->{$self} = $$value;
139             }
140             else {
141 50         110 $slot_of_ref->{$self} = $value;
142             }
143              
144 64 0 0     200 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         113 my $dest = $name_of{$self};
150              
151             {
152 7     7   60 no strict;
  7         11  
  7         349  
  64         83  
153 7     7   51 no warnings 'redefine';
  7         22  
  7         1431  
154 64         82 *{$dest} = $value;
  64         144  
155             }
156              
157 64         170 return $slot_of_ref->{$self};
158             }
159              
160             sub delete {
161 8     8 1 27 my ($self, $slot_to_delete) = @_;
162 8         10 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       18 if (defined $slot_to_delete) {
168 8         15 my $glob_slot = $Method_To_Slot_Of{$slot_to_delete};
169 8         12 $storage_ref = $Slot_To_Storage_Of{$glob_slot};
170              
171 8         20 delete $storage_ref->{$self};
172             }
173              
174             # Delete the glob so it can be reconstituted.
175 8         15 my $dest = $name_of{$self};
176 8         58 my ($package, $symbol) = ($dest =~ /(.*::)*(.*)/);
177 8 50       19 $package = __PACKAGE__.'::' unless $package;
178 8         9 my $globref;
179              
180             {
181 7     7   59 no strict;
  7         13  
  7         737  
  8         11  
182 8         11 $globref = \%{$package};
  8         20  
183 8         13 undef *{$dest};
  8         38  
184             }
185              
186             # If no argument, deleting everything.
187 8 50       19 return unless defined $slot_to_delete;
188              
189 8         26 for my $method (keys %Method_To_Slot_Of) {
190 48 100       119 next if $method eq $slot_to_delete;
191              
192 40         55 $storage_ref = $Slot_To_Storage_Of{$Method_To_Slot_Of{$method}};
193 40         68 my $value = $storage_ref->{$self};
194 40 100       65 $value = \$value if $method eq 'scalar';
195              
196             {
197 7     7   47 no warnings 'redefine';
  7         12  
  7         267  
  40         45  
198 7     7   47 no strict 'refs';
  7         21  
  7         663  
199              
200             $globref->{$symbol} = $value
201 40 100       92 if defined $storage_ref->{$self};
202             }
203             }
204             }
205             }
206              
207             1; # Magic true value required at end of module
208             __END__