File Coverage

blib/lib/Hash/Objectify.pm
Criterion Covered Total %
statement 68 68 100.0
branch 16 16 100.0
condition 4 12 33.3
subroutine 16 17 94.1
pod 2 2 100.0
total 106 115 92.1


line stmt bran cond sub pod time code
1 2     2   30266 use 5.008001;
  2         6  
2 2     2   5 use strict;
  2         2  
  2         30  
3 2     2   5 use warnings;
  2         2  
  2         65  
4              
5             package Hash::Objectify;
6              
7             # ABSTRACT: Create objects from hashes on the fly
8              
9             our $VERSION = '0.008';
10              
11 2     2   6 use Carp;
  2         2  
  2         95  
12 2     2   9 use Exporter 5.57 'import';
  2         24  
  2         58  
13 2     2   6 use Scalar::Util qw/blessed/;
  2         5  
  2         267  
14              
15             our @EXPORT = qw/objectify/;
16             our @EXPORT_OK = qw/objectify_lax/;
17              
18             my %CACHE;
19             my $COUNTER = 0;
20              
21             sub objectify {
22 12     12 1 2388 my ( $ref, $package ) = @_;
23 12         15 my $type = ref $ref;
24 12 100       23 unless ( $type eq 'HASH' ) {
25 3 100       17 $type =
    100          
26             $type eq '' ? "a scalar value"
27             : blessed($ref) ? "an object of class $type"
28             : "a reference of type $type";
29 3         250 croak "Error: Can't objectify $type";
30             }
31 9 100       13 if ( defined $package ) {
32 2     2   7 no strict 'refs';
  2         2  
  2         134  
33 2 100       11 push @{ $package . '::ISA' }, 'Hash::Objectified'
  1         10  
34             unless $package->isa('Hash::Objectified');
35             }
36             else {
37 7         11 my ( $caller, undef, $line ) = caller;
38 7         22 my $cachekey = join "", sort keys %$ref;
39 7 100       18 if ( !defined $CACHE{$caller}{$line}{$cachekey} ) {
40 2     2   6 no strict 'refs';
  2         2  
  2         212  
41 6         11 $package = $CACHE{$caller}{$line}{$cachekey} = "Hash::Objectified$COUNTER";
42 6         6 $COUNTER++;
43 6         4 @{ $package . '::ISA' } = 'Hash::Objectified';
  6         61  
44             }
45             else {
46 1         2 $package = $CACHE{$caller}{$line}{$cachekey};
47             }
48             }
49 9         32 return bless {%$ref}, $package;
50             }
51              
52             sub objectify_lax {
53 1     1 1 2 my ( $ref, $package ) = @_;
54 1         2 my $obj = objectify( $ref, $package );
55 1   33     6 $package ||= ref($obj);
56             {
57 2     2   6 no strict 'refs';
  2         2  
  2         105  
  1         0  
58 1         2 unshift @{ $package . '::ISA' }, 'Hash::Objectified::Lax';
  1         8  
59             }
60 1         3 return $obj;
61             }
62              
63             package Hash::Objectified;
64              
65 2     2   821 use Class::XSAccessor;
  2         3377  
  2         8  
66              
67             our $AUTOLOAD;
68              
69             sub can {
70 5     5   1232 my ( $self, $key ) = @_;
71 5 100 33     26 return undef unless ref $self && exists $self->{$key}; ## no critic
72 4         17 $self->$key; # install accessor if not installed
73 4         16 return $self->SUPER::can($key);
74             }
75              
76             sub AUTOLOAD {
77 8     8   1055 my $self = shift;
78 8         8 my $method = $AUTOLOAD;
79 8         29 $method =~ s/.*:://;
80 8 100 33     36 if ( ref $self && exists $self->{$method} ) {
81 6         24 Class::XSAccessor->import(
82             accessors => { $method => $method },
83             class => ref $self
84             );
85 6         566 return $self->$method(@_);
86             }
87             else {
88 2         10 return $self->_handle_missing($method);
89             }
90             }
91              
92             sub _handle_missing {
93 1     1   1 my ( $self, $method ) = @_;
94 1   33     3 my $class = ref $self || $self;
95 1         9 die qq{Can't locate object method "$method" via package "$class"};
96             }
97              
98       0     sub DESTROY { } # because we AUTOLOAD, we need this too
99              
100             package Hash::Objectified::Lax;
101              
102             sub _handle_missing {
103 1     1   3 return undef; ## no critic
104             }
105              
106             1;
107              
108              
109             # vim: ts=4 sts=4 sw=4 et:
110              
111             __END__