File Coverage

blib/lib/Class/Constant.pm
Criterion Covered Total %
statement 88 93 94.6
branch 21 26 80.7
condition 9 14 64.2
subroutine 18 19 94.7
pod n/a
total 136 152 89.4


line stmt bran cond sub pod time code
1             package Class::Constant;
2              
3 7     7   162280 use warnings;
  7         15  
  7         303  
4 7     7   38 use strict;
  7         13  
  7         2282  
5              
6             our $VERSION = '0.06';
7              
8             my %ordinal_for_data;
9             my %data_by_ordinal;
10              
11             sub import {
12 10     10   133 my ($pkg, @args) = @_;
13              
14 10         28 my $caller = caller;
15              
16 10   100     77 $ordinal_for_data{$caller} ||= 0;
17              
18 10         78 my $start_ordinal = $ordinal_for_data{$caller};
19              
20 10         16 my %data;
21 10         21 my $value = 0;
22 10         24 for my $arg (@args) {
23 57 100       213 if ($arg =~ /^[A-Z][A-Z0-9_]*$/) {
24 35 100       101 if (exists $data{name}) {
25 26         109 my %data_copy = %data;
26 26         83 $data_by_ordinal{$caller}->[$data{ordinal}] = \%data_copy;
27             }
28              
29 35         80 %data = ();
30              
31 35         56 $data{name} = $arg;
32              
33 35         64 $data{ordinal} = $ordinal_for_data{$caller};
34 35         55 $ordinal_for_data{$caller}++;
35              
36 35         42 $data{object} = \do { my $x = $data{ordinal} };
  35         89  
37              
38 35         55 $data{value} = $value;
39 35         44 $value++;
40              
41 35         73 next;
42             }
43              
44 22 100       48 if (ref $arg eq "HASH") {
45 8         16 $data{methods} = $value = $arg;
46 8         9 $value++;
47              
48 8         14 next;
49             }
50              
51 14         25 $data{value} = $value = $arg;
52 14         30 $value++;
53             }
54              
55 10 100       39 if (exists $data{name}) {
56 9         43 my %data_copy = %data;
57 9         29 $data_by_ordinal{$caller}->[$data{ordinal}] = \%data_copy;
58             }
59              
60 10         37 for my $ordinal ($start_ordinal .. $ordinal_for_data{$caller}-1) {
61 35         67 my $data = $data_by_ordinal{$caller}->[$ordinal];
62              
63 35         41 do {
64 7     7   49 no strict "refs";
  7         21  
  7         572  
65 35     68   123 *{$caller."::".$data->{name}} = sub { bless $data->{object}, $caller };
  35         244  
  68         4504  
66             };
67             }
68              
69 10 100 100     1604 if ($start_ordinal == 0 and $ordinal_for_data{$caller} > 0) {
70 8         13 do {
71 7     7   44 no strict "refs";
  7         21  
  7         1583  
72              
73 8         15 unshift @{$caller."::ISA"}, "Class::Constant::Object";
  8         108  
74              
75 8         8689 *{$caller."::by_ordinal"} = sub {
76 7 50   7   34 return if @_ < 2;
77 7 100       31 if (not exists $data_by_ordinal{$caller}->[$_[1]]) {
78 1         14 require Carp;
79 1   33     236 Carp::croak("Can't locate constant with ordinal \"$_[1]\" in package \"".(ref($_[0])||$_[0])."\"");
80             }
81 6         41 return bless $data_by_ordinal{$caller}->[$_[1]]->{object}, $caller;
82 8         43 };
83             };
84             }
85             }
86              
87              
88             package
89             Class::Constant::Object;
90              
91 7     7   42 use Scalar::Util qw(refaddr blessed);
  7         12  
  7         1589  
92              
93             use overload
94 22     22   73 q{""} => sub { (shift)->as_string(@_) },
95 9     9   50 q{==} => sub { !!((shift)->equals(@_)) },
96 6     6   20 q{!=} => sub { !((shift)->equals(@_)) },
97 22     22   2885 q{eq} => sub { !!((shift)->equals(@_)) },
98 7     7   11342 q{ne} => sub { !((shift)->equals(@_)) };
  7     0   7281  
  7         95  
  0         0  
99              
100             sub as_string {
101 21     21   49 return "$data_by_ordinal{ref $_[0]}->[${$_[0]}]->{value}";
  21         256  
102             }
103              
104             sub equals {
105 37 100 66 37   291 if (blessed $_[1] and $_[1]->isa(__PACKAGE__)) {
106 15 100       638 return (refaddr $_[0] == refaddr $_[1]) ? 1 : 0;
107             }
108              
109 22         76 return "".$_[0] eq "".$_[1];
110             }
111              
112             sub get_ordinal {
113 6     6   8 return ${$_[0]};
  6         130  
114             }
115              
116             sub AUTOLOAD {
117 16     16   30 my ($self) = @_;
118              
119 7     7   1879 use vars qw($AUTOLOAD);
  7         15  
  7         2393  
120 16         88 my ($pkg, $method) = $AUTOLOAD =~ m/^(.*)::(.*)/;
121              
122 16 50       53 return if $method =~ m/^[A-Z]+$/;
123              
124 16 50       50 if ($method !~ m/^get_/) {
125 0         0 require Carp;
126 0         0 Carp::croak("Can't locate object method \"$method\" via package \"$pkg\"");
127             }
128              
129 16         55 my ($name) = $method =~ m/^get_(.*)/;
130              
131 16         33 my $data = $data_by_ordinal{ref $_[0]}->[${$_[0]}];
  16         99  
132 16 50       41 return if not $data;
133              
134 16 50 33     79 if (not exists $data->{methods} or not exists $data->{methods}->{$name}) {
135 0         0 require Carp;
136 0         0 Carp::croak("Can't locate named constant \"$name\" for \"" .ref($_[0]). "::$data->{name}\"");
137             }
138              
139 16         85 return $data->{methods}->{$name};
140             }
141              
142             1;
143              
144             __END__