File Coverage

blib/lib/Object/Properties.pm
Criterion Covered Total %
statement 86 86 100.0
branch 17 18 94.4
condition 3 3 100.0
subroutine 21 21 100.0
pod n/a
total 127 128 99.2


line stmt bran cond sub pod time code
1 2     2   32054 use 5.006; # for us
  2         6  
2 2     2   16 use 5.008008; # for Sentinel
  2         3  
3 2     2   5 use strict;
  2         5  
  2         40  
4 2     2   6 use warnings;
  2         1  
  2         89  
5              
6             package Object::Properties;
7             $Object::Properties::VERSION = '1.002';
8             # ABSTRACT: minimal-ceremony class builder
9              
10 2     2   840 use Sentinel ();
  2         1537  
  2         1977  
11              
12             sub _make_init {
13 7     7   9 my @field = @{ $_[0] };
  7         11  
14 7         7 my @setter = @{ $_[1] };
  7         8  
15             return sub {
16 42     42   5566 my $self = shift;
17 42         42 my ( $hash ) = @_;
18 42         26 my ( @v, @s );
19 42         79 for my $i ( 0 .. $#field ) {
20 138 100       201 next unless exists $hash->{ $field[ $i ] };
21 113         87 push @s, $setter[ $i ];
22 113         126 push @v, delete $hash->{ $field[ $i ] };
23             }
24 42 50       77 delete @$self{ @field } if $hash != $self;
25 42         52 for my $i ( 0 .. $#v ) { $self->$_( $v[$i] ) for $s[$i] }
  113         353  
26 7         43 };
27             }
28              
29             sub _make_getter {
30 27     27   29 my ( $prop ) = @_;
31 27     8   45 return sub { $_[0]{ $prop } };
  8         2629  
32             }
33              
34             sub _make_getter_setter {
35 1     1   1 my ( $prop ) = @_;
36 1     3   3 return sub : lvalue { $_[0]{ $prop } };
  3         2013  
37             }
38              
39             sub _make_setter {
40 23     23   26 my ( $prop, $munger ) = @_;
41             return sub {
42 116     116   117 local $Carp::Internal{ (__PACKAGE__) } = 1;
43 116         130 $_[0]{ $prop } = $_, return for &$munger;
44 23         64 };
45             }
46              
47             sub _make_accessor {
48 3     3   3 my ( $getter, $setter ) = @_;
49 3     7   8 return sub : lvalue { Sentinel::sentinel get => $getter, set => $setter, obj => $_[0] };
  7         42  
50             }
51              
52             sub import {
53 9     9   3703 my $class = shift;
54 9         16 my $pkg = caller;
55              
56 9         10 my ( @prop, %ro, %setter );
57 9         19 for ( @_ ) {
58 51 100 100     156 if ( @prop and 'CODE' eq ref ) {
59 23         33 $setter{ $prop[-1] } = _make_setter $prop[-1], $_;
60 23         24 next;
61             }
62 28 100       104 die "Invalid accessor name '$_'" unless /\A([+]?)([^\W\d]\w*)\z/;
63 27 100       69 $ro{ $2 } = 1 unless $1;
64 27         41 push @prop, $2;
65             }
66              
67 8         12 for my $prop ( @prop ) {
68 27         31 my $getter = _make_getter $prop;
69 27         48 my $setter = $setter{ $prop };
70             my $accessor
71 27 100       42 = $ro{ $prop } ? $getter
    100          
72             : $setter ? _make_accessor $getter, $setter
73             : _make_getter_setter $prop;
74 2     2   11 { no strict 'refs'; *{ $pkg.'::'.$prop } = $accessor }
  2         2  
  2         158  
  27         21  
  27         12  
  27         121  
75             }
76              
77 8 100       11 if ( my @sprop = grep { exists $setter{ $_ } } @prop ) {
  27         52  
78 7         21 my $init = _make_init \@sprop, [ @setter{ @sprop } ];
79 2     2   8 { no strict 'refs'; *{ $pkg.'::PROPINIT' } = $init }
  2         6  
  2         63  
  7         10  
  7         5  
  7         16  
80             }
81              
82 2     2   7 my $ISA = do { no strict 'refs'; \@{ $pkg.'::ISA' } };
  2         2  
  2         203  
  8         7  
  8         5  
  8         19  
83 8 100       39 @$ISA = __PACKAGE__ . '::Base' unless @$ISA;
84              
85 8         75 return 1;
86             }
87              
88             package Object::Properties::Base;
89             $Object::Properties::Base::VERSION = '1.002';
90 2     2   966 use NEXT ();
  2         6993  
  2         122  
91              
92             sub new {
93 42     42   10731 my $class = shift;
94 42         93 my $self = bless { @_ }, $class;
95 42         58 local $Carp::Internal{ (__PACKAGE__) } = 1;
96 42         182 $self->EVERY::LAST::PROPINIT( $self );
97 40         311 return $self;
98             }
99              
100             1;
101              
102             __END__