File Coverage

blib/lib/Object/HashBase.pm
Criterion Covered Total %
statement 69 77 89.6
branch 24 30 80.0
condition 6 15 40.0
subroutine 13 14 92.8
pod 1 1 100.0
total 113 137 82.4


line stmt bran cond sub pod time code
1             package Object::HashBase;
2 2     2   45115 use strict;
  2         11  
  2         50  
3 2     2   9 use warnings;
  2         4  
  2         91  
4              
5             our $VERSION = '0.006';
6             our $HB_VERSION = $VERSION;
7             # The next line is for inlining
8             # <-- START -->
9              
10             require Carp;
11             {
12 2     2   9 no warnings 'once';
  2         3  
  2         123  
13             $Carp::Internal{+__PACKAGE__} = 1;
14             }
15              
16             BEGIN {
17             # these are not strictly equivalent, but for out use we don't care
18             # about order
19             *_isa = ($] >= 5.010 && require mro) ? \&mro::get_linear_isa : sub {
20 2     2   13 no strict 'refs';
  2         5  
  2         182  
21 0         0 my @packages = ($_[0]);
22 0         0 my %seen;
23 0         0 for my $package (@packages) {
24 0         0 push @packages, grep !$seen{$_}++, @{"$package\::ISA"};
  0         0  
25             }
26 0         0 return \@packages;
27             }
28 2 50 33 2   630 }
29              
30             my %STRIP = (
31             '^' => 1,
32             '-' => 1,
33             );
34              
35             sub import {
36 21     21   940 my $class = shift;
37 21         40 my $into = caller;
38              
39             # Make sure we list the OLDEST version used to create this class.
40 21   33     52 my $ver = $Object::HashBase::HB_VERSION || $Object::HashBase::VERSION;
41 21 50 33     67 $Object::HashBase::VERSION{$into} = $ver if !$Object::HashBase::VERSION{$into} || $Object::HashBase::VERSION{$into} > $ver;
42              
43 21         80 my $isa = _isa($into);
44 21   50     84 my $attr_list = $Object::HashBase::ATTR_LIST{$into} ||= [];
45 21   50     67 my $attr_subs = $Object::HashBase::ATTR_SUBS{$into} ||= {};
46              
47             my %subs = (
48             ($into->can('new') ? () : (new => \&_new)),
49 6 50       29 (map %{$Object::HashBase::ATTR_SUBS{$_} || {}}, @{$isa}[1 .. $#$isa]),
  21         50  
50             (
51             map {
52 21 100       161 my $p = substr($_, 0, 1);
  39         75  
53 39         45 my $x = $_;
54 39 100       75 substr($x, 0, 1) = '' if $STRIP{$p};
55 39         56 push @$attr_list => $x;
56 39         73 my ($sub, $attr) = (uc $x, $x);
57 0     0   0 $sub => ($attr_subs->{$sub} = sub() { $attr }),
58 16     16   55 $attr => sub { $_[0]->{$attr} },
59 1     1   119 $p eq '-' ? ("set_$attr" => sub { Carp::croak("'$attr' is read-only") })
60 1     1   62 : $p eq '^' ? ("set_$attr" => sub { Carp::carp("set_$attr() is deprecated"); $_[0]->{$attr} = $_[1] })
  1         11  
61 39 100   7   413 : ("set_$attr" => sub { $_[0]->{$attr} = $_[1] }),
  7 100       18  
62             } @_
63             ),
64             );
65              
66 2     2   13 no strict 'refs';
  2         10  
  2         689  
67 21         77 *{"$into\::$_"} = $subs{$_} for keys %subs;
  143         1485  
68             }
69              
70             sub attr_list {
71 3     3 1 5 my $class = shift;
72              
73 3         9 my $isa = _isa($class);
74              
75 3         3 my %seen;
76 15         37 my @list = grep { !$seen{$_}++ } map {
77 3         6 my @out;
  6         7  
78              
79 6 50 50     17 if (0.004 > ($Object::HashBase::VERSION{$_} || 0)) {
80 0         0 Carp::carp("$_ uses an inlined version of Object::HashBase too old to support attr_list()");
81             }
82             else {
83 6         8 my $list = $Object::HashBase::ATTR_LIST{$_};
84 6 50       12 @out = $list ? @$list : ()
85             }
86              
87 6         16 @out;
88             } reverse @$isa;
89              
90 3         12 return @list;
91             }
92              
93             sub _new {
94 11     11   20 my $class = shift;
95              
96 11         13 my $self;
97              
98 11 100       25 if (@_ == 1) {
99 3         4 my $arg = shift;
100 3         7 my $type = ref($arg);
101              
102 3 100       4 if ($type eq 'HASH') {
103 1         4 $self = bless({%$arg}, $class)
104             }
105             else {
106 2 50       6 Carp::croak("Not sure what to do with '$type' in $class constructor")
107             unless $type eq 'ARRAY';
108              
109 2         2 my %proto;
110 2         4 my @attributes = attr_list($class);
111 2         5 while (@$arg) {
112 9         11 my $val = shift @$arg;
113 9 100       93 my $key = shift @attributes or Carp::croak("Too many arguments for $class constructor");
114 8         17 $proto{$key} = $val;
115             }
116              
117 1         3 $self = bless(\%proto, $class);
118             }
119             }
120             else {
121 8         22 $self = bless({@_}, $class);
122             }
123              
124             $Object::HashBase::CAN_CACHE{$class} = $self->can('init')
125 10 100       38 unless exists $Object::HashBase::CAN_CACHE{$class};
126              
127 10 100       29 $self->init if $Object::HashBase::CAN_CACHE{$class};
128              
129 10         29 $self;
130             }
131              
132             1;
133              
134             __END__