File Coverage

blib/lib/Class/Constant.pm
Criterion Covered Total %
statement 91 96 94.7
branch 26 32 81.2
condition 9 14 64.2
subroutine 19 20 95.0
pod n/a
total 145 162 89.5


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