File Coverage

blib/lib/Unicode/Char.pm
Criterion Covered Total %
statement 63 69 91.3
branch 21 26 80.7
condition n/a
subroutine 14 17 82.3
pod 4 6 66.6
total 102 118 86.4


line stmt bran cond sub pod time code
1             package Unicode::Char;
2 4     4   139984 use 5.008001;
  4         18  
  4         219  
3 4     4   22 use strict;
  4         7  
  4         140  
4 4     4   34 use warnings;
  4         18  
  4         122  
5 4     4   22 use Carp;
  4         5  
  4         4017  
6              
7             our $VERSION = sprintf "%d.%02d", q$Revision: 0.2 $ =~ /(\d+)/g;
8             our $DEBUG = 0;
9              
10             our %Name2Chr;
11             our %Chr2Name;
12              
13             sub _init{
14 4 100   4   13 return if %Name2Chr;
15 1         47647 my $name_pl = do 'unicore/Name.pl'; # famous cheat;
16 1         20126 for my $line (split /\n/, $name_pl){
17 24222         44887 chomp $line;
18 24222         149521 my ($hex, $name) = ($line =~ /^([0-9A-Fa-f]+)\s+(.*)/);
19 24222 50       61971 next if $name =~ /[a-z]/; # range, not character
20 24222         49933 my $chr = chr(hex($hex));
21 24222         87765 $Name2Chr{$name} = $chr;
22 24222         94298 $Chr2Name{$chr} = $name;
23             }
24             }
25              
26             sub new {
27 10     10 0 50 my $pkg = shift;
28 10         18 return bless \eval{ my $scalar }, $pkg;
  10         49  
29             }
30              
31             sub valid($$){
32 13     13 0 36 my ($self,$ord) = @_;
33 13 100       50 return 0 if $ord < 0;
34 12 100       46 return 1 if $ord < 0xDC00; # BMP before surrogates
35 7 100       34 return 0 if $ord <= 0xDFFF; # surrogates
36 5 100       21 return 1 if $ord < 0xFFFF; # BMP after surrogates
37 3 100       15 return 0 if $ord == 0xFFFF; # U+FFFF is invalid
38 2 100       11 return 1 if $ord <= 0x10FFFF; # and to the max;
39 1         5 return 0;
40             }
41              
42             sub names($$){
43 0     0 1 0 my ($self,$str) = @_;
44 0         0 _init;
45 0         0 return map { $Chr2Name{chr($_)} } unpack("U*", $str);
  0         0  
46             }
47              
48             sub name($$){
49 0     0 1 0 return ($_[0]->names($_[1]))[0];
50             }
51              
52             sub u($$){
53 3     3 1 7 my ($self, $hex) = @_;
54 3         7 my $ord = hex($hex);
55 3 50       8 croak "$ord is invalid" unless $self->valid($ord);
56 3         10 return chr($ord);
57             }
58              
59             sub n($$){
60 4     4 1 9 my ($self, $name) = @_;
61 4         10 _init();
62             # canonicalize;
63 4         1693 $name =~ tr/_/ /;
64 4         14 $name = uc($name);
65 4         19 return $Name2Chr{$name};
66             }
67              
68 0     0   0 sub DESTROY{} # so AUTOLOAD will not handle this
69              
70             sub AUTOLOAD{
71 7     7   39 my $method = our $AUTOLOAD;
72 7 50       25 $DEBUG and carp $method;
73 7         48 $method =~ s/.*:://o;
74 7 100       33 if ($method =~ s/^u_?//o){
75 3         7 my $chr = __PACKAGE__->new()->u($method);
76 3 50       14 defined $chr or croak "U$method is invalid!";
77 4     4   28 no strict 'refs';
  4         8  
  4         756  
78 3     3   10 *{$AUTOLOAD} = sub { $chr };
  3         12  
  3         15  
79 3         10 goto &$AUTOLOAD;
80             }
81             else{
82 4         17 my $chr = __PACKAGE__->new()->n($method);
83 4 50       21 defined $chr or croak qq(There is no character named "$method");
84 4     4   23 no strict 'refs';
  4         8  
  4         476  
85 4     4   22 *{$AUTOLOAD} = sub { $chr };
  4         21  
  4         29  
86 4         19 goto &$AUTOLOAD;
87             }
88             }
89              
90             1;
91             __END__