File Coverage

blib/lib/Symbol/Global/Name.pm
Criterion Covered Total %
statement 45 45 100.0
branch 25 28 89.2
condition 7 10 70.0
subroutine 6 6 100.0
pod 1 1 100.0
total 84 90 93.3


line stmt bran cond sub pod time code
1 1     1   39178 use 5.008;
  1         4  
  1         46  
2 1     1   6 use strict;
  1         2  
  1         38  
3 1     1   7 use warnings;
  1         7  
  1         296  
4              
5             package Symbol::Global::Name;
6              
7             our $VERSION = '0.05';
8              
9             =head1 NAME
10              
11             Symbol::Global::Name - finds name and type of a global variable
12              
13             =head1 SYNOPSIS
14              
15             package My;
16             our $VERSION = '0.1';
17              
18             use Symbol::Global::Name;
19             print Symbol::Global::Name->find( \$VERSION );
20              
21             # prints '$My::VERSION'
22              
23             =head1 DESCRIPTION
24              
25             Lookups symbol table to find an element by reference.
26              
27             =cut
28            
29             our %REF_SYMBOLS = (
30             SCALAR => '$',
31             ARRAY => '@',
32             HASH => '%',
33             CODE => '&',
34             );
35              
36             =head1 METHODS
37              
38             =head2 find
39              
40             Symbol::Global::Name->find( \$VERSION );
41             Symbol::Global::Name->find( \$VERSION, package => 'My::Package' );
42             Symbol::Global::Name->find( reference => \$VERSION );
43             Symbol::Global::Name->find( reference => \$VERSION, package => 'My::Package' );
44              
45             Takes a reference and optional package name. Returns name
46             of the referenced variable as long as it's in the package
47             or sub-package and it's a global variable. Returned name
48             is prefixed with type sigil, eg. '$', '@', '%', '&' or '*'.
49              
50             =cut
51              
52             my $last_package = '';
53             sub find {
54 6     6 1 2473 my $self = shift;
55 6 50       36 my %args = (
56             @_%2? ( reference => @_ ) : (@_),
57             );
58              
59 6         13 my $package = $args{'package'};
60              
61 6 100 66     36 if ( !$package && $last_package ) {
62 5         17 my $tmp = $self->_find( $args{'reference'}, $last_package );
63 5 100       112 return $tmp if $tmp;
64             }
65 3   50     16 $package ||= 'main::';
66 3 50       13 $package .= '::' unless substr( $package, -2 ) eq '::';
67 3         11 return $self->_find( $args{'reference'}, $package );
68             }
69              
70             sub _find {
71 295     295   454 my $self = shift;
72 295         343 my $ref = shift;
73 295         292 my $pack = shift;
74              
75 1     1   6 no strict 'refs';
  1         2  
  1         347  
76 295         330 my $name = undef;
77              
78             # scan $pack's nametable(hash)
79 295         286 foreach my $k ( keys %{$pack} ) {
  295         3014  
80              
81             # The hash for main:: has a reference to itself
82 4669 100       15236 next if $k eq 'main::';
83              
84             # if the entry has a trailing '::' then
85             # it is a link to another name space
86 4667 100       10412 if ( substr( $k, -2 ) eq '::') {
87 287 100       1555 $name = $self->_find( $ref, $pack eq 'main::'? $k : $pack.$k );
88 287 100       1015 return $name if $name;
89             }
90              
91             # entry of the table with references to
92             # SCALAR, ARRAY... and other types with
93             # the same name
94 4663         4414 my $entry = ${$pack}{$k};
  4663         19344  
95 4663 50       9997 next unless $entry;
96              
97             # Inlined constants are simplified in the symbol table --
98             # namely, when possible, you only get a reference back in
99             # $entry, rather than a full GLOB. In 5.10, scalar
100             # constants began being inlined this way; starting in 5.20,
101             # list constants are also inlined. Notably, ref(GLOB) is
102             # undef, but inlined constants are currently either REF,
103             # SCALAR, or ARRAY.
104 4663 100       18600 next if ref($entry);
105              
106 4503         8471 my $ref_type = ref($ref);
107              
108             # regex/arrayref/hashref/coderef are stored in SCALAR glob
109 4503 100       8717 $ref_type = 'SCALAR' if $ref_type eq 'REF';
110              
111 4503         9877 my $entry_ref = *{$entry}{ $ref_type };
  4503         14258  
112 4503 100 100     35530 next if ref $entry_ref && ref $entry_ref ne ref $ref;
113 3481 100       6288 next unless $entry_ref;
114              
115             # if references are equal then we've found
116 3472 100       18791 if ( $entry_ref == $ref ) {
117 6         12 $last_package = $pack;
118 6   50     50 return ( $REF_SYMBOLS{ $ref_type } || '*' ) . $pack . $k;
119             }
120             }
121 285         2179 return '';
122             }
123              
124             =head1 AUTHOR
125              
126             Ruslan Zakirov Eruz@bestpractical.comE
127              
128             =head1 LICENSE
129              
130             Under the same terms as perl itself.
131              
132             =cut
133              
134             1;