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   30164 use 5.008001;
  2         4  
2 2     2   6 use strict;
  2         1  
  2         28  
3 2     2   4 use warnings;
  2         2  
  2         67  
4              
5             package Hash::Objectify;
6              
7             # ABSTRACT: Create objects from hashes on the fly
8              
9             our $VERSION = '0.007'; # TRIAL
10              
11 2     2   6 use Carp;
  2         0  
  2         82  
12 2     2   6 use Exporter 5.57 'import';
  2         18  
  2         57  
13 2     2   7 use Scalar::Util qw/blessed/;
  2         5  
  2         285  
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 3160 my ( $ref, $package ) = @_;
23 12         17 my $type = ref $ref;
24 12 100       23 unless ( $type eq 'HASH' ) {
25 3 100       291 $type =
    100          
26             $type eq '' ? "a scalar value"
27             : blessed($ref) ? "an object of class $type"
28             : "a reference of type $type";
29 3         291 croak "Error: Can't objectify $type";
30             }
31 9 100       12 if ( defined $package ) {
32 2     2   8 no strict 'refs';
  2         2  
  2         158  
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   8 no strict 'refs';
  2         2  
  2         215  
41 6         14 $package = $CACHE{$caller}{$line}{$cachekey} = "Hash::Objectified$COUNTER";
42 6         5 $COUNTER++;
43 6         4 @{ $package . '::ISA' } = 'Hash::Objectified';
  6         59  
44             }
45             else {
46 1         1 $package = $CACHE{$caller}{$line}{$cachekey};
47             }
48             }
49 9         31 return bless {%$ref}, $package;
50             }
51              
52             sub objectify_lax {
53 1     1 1 2 my ( $ref, $package ) = @_;
54 1         1 my $obj = objectify( $ref, $package );
55 1   33     6 $package ||= ref($obj);
56             {
57 2     2   6 no strict 'refs';
  2         2  
  2         107  
  1         1  
58 1         1 unshift @{ $package . '::ISA' }, 'Hash::Objectified::Lax';
  1         8  
59             }
60 1         2 return $obj;
61             }
62              
63             package Hash::Objectified;
64              
65 2     2   765 use Class::XSAccessor;
  2         3290  
  2         8  
66              
67             our $AUTOLOAD;
68              
69             sub can {
70 5     5   1755 my ( $self, $key ) = @_;
71 5 100 33     26 return undef unless ref $self && exists $self->{$key}; ## no critic
72 4         20 $self->$key; # install accessor if not installed
73 4         15 return $self->SUPER::can($key);
74             }
75              
76             sub AUTOLOAD {
77 8     8   1634 my $self = shift;
78 8         8 my $method = $AUTOLOAD;
79 8         37 $method =~ s/.*:://;
80 8 100 33     40 if ( ref $self && exists $self->{$method} ) {
81 6         28 Class::XSAccessor->import(
82             accessors => { $method => $method },
83             class => ref $self
84             );
85 6         942 return $self->$method(@_);
86             }
87             else {
88 2         25 return $self->_handle_missing($method);
89             }
90             }
91              
92             sub _handle_missing {
93 1     1   2 my ( $self, $method ) = @_;
94 1   33     3 my $class = ref $self || $self;
95 1         11 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__