File Coverage

blib/lib/Object/Properties.pm
Criterion Covered Total %
statement 91 91 100.0
branch 17 18 94.4
condition 3 3 100.0
subroutine 22 22 100.0
pod n/a
total 133 134 99.2


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