File Coverage

lib/accessors/fast.pm
Criterion Covered Total %
statement 89 101 88.1
branch 17 36 47.2
condition 9 21 42.8
subroutine 19 19 100.0
pod 4 4 100.0
total 138 181 76.2


line stmt bran cond sub pod time code
1             # Copyright (c) 2009 Mons Anderson . All rights reserved
2             # This program is free software; you can redistribute it and/or
3             # modify it under the same terms as Perl itself.
4             package accessors::fast;
5              
6             =head1 NAME
7              
8             accessors::fast - Compiletime accessors using Class::Accessor::Fast
9              
10             =cut
11              
12             our $VERSION = '0.03';
13              
14             =head1 VERSION
15              
16             Version 0.03
17              
18             =head1 SYNOPSIS
19              
20             package My::Simple::Package;
21             use accessors::fast qw(field1 field2);
22            
23             # constructor is private, redefine only init;
24             sub init {
25             my $self = shift;
26             my %args = @_;
27             $self->field1($args{arg1});
28             }
29            
30             package main;
31             my $o = My::Simple::Package->new( arg1 => 'some value' );
32             print $o->field1; # some value
33            
34             for ($o->field_list) {
35             printf "object have field %s with value %s\n", $_, $o->$_;
36             }
37              
38             =head1 DESCRIPTION
39              
40             This module was created as an alternative to C, and uses L as a base
41              
42             Creates accessors at compiletime
43              
44             Have own default C method: it creates object as a blessed hash, then locks keys to defined field list, and invoke C.
45             So, recommended usage inside packages, is access by hash keys (it's 3 times faster then accessor).
46             Since keys are locked, you will not suffer from autovivification. Public interface recommended to be documented as accessors.
47              
48             Uses L
49              
50             =head1 METHODS
51              
52             All methods inherited from L. Own methods defined below
53              
54             =head2 new( ARGS )
55              
56             Creates blessed hash, locks it keys to current fields of this package, and invoke C method with C
57              
58             =head2 init( ARGS )
59              
60             Recommended to redefine in subclasses. Will be invoked by inherited C
61              
62             =head2 field_list
63              
64             Since this module keeps information about object fields, it can return it.
65              
66             for ($o->field_list) {
67             printf "%s: %s\n",$_,$o->$_;
68             }
69              
70             =head1 FEATURES
71              
72             This module uses L, so it behaviour could be affected by L
73              
74             =head2 TIE [ = 0 ]
75              
76             Use tied hash, instead of LC<::lock_keys>. Much more slower, but could help during development.
77              
78             Could be enabled by
79              
80             # your main program/main.pl
81             use constant::abs 'accessors::fast::TIE' => 1;
82              
83             =head2 CONFESS [ = 0 ]
84              
85             use Carp::confess instead of croak on error conditions
86              
87             Could be enabled by
88              
89             # your main program/main.pl
90             use constant::abs 'accessors::fast::CONFESS' => 1;
91              
92             =head2 warnings
93              
94             This module uses L. So, warnings from it could be disabled by
95              
96             no warnings 'accessors::fast';
97              
98             =cut
99              
100 3     3   11291 use 5.008008;
  3         12  
  3         258  
101 3     3   16 use strict;
  3         5  
  3         99  
102 3     3   25 use warnings;
  3         5  
  3         88  
103 3     3   14 use warnings::register;
  3         5  
  3         501  
104             use constant::def {
105 3         24 DEBUG => 0,
106             CONFESS => 0,
107             TIE => 0,
108 3     3   2503 };
  3         791  
109             our $ME;
110              
111 3     3   431 use base ();
  3         6  
  3         364  
112             BEGIN {
113 3     3   8 $ME = __PACKAGE__;
114             !TIE and eval q{ use Class::Accessor::Fast::XS; 1 }
115 3         801 and do{ base->import('Class::Accessor::Fast::XS'); 1 }
  3         2940  
116             or
117 1         52 eval { require Class::Accessor::Fast; 1 }
  1         3  
118 3 50 33 2   158 and do{ base->import('Class::Accessor::Fast'); 1 }
  1   0     390  
  0   33     0  
  2         1826  
  2         10445  
  2         27  
119             or die "accessors::fast can't find neither Class::Accessor::Fast::XS nor Class::Accessor::Fast. ".
120             "Please install one.\n";
121 2         43 TIE and require accessors::fast::tie;
122             }
123              
124 3     3   2507 use Hash::Util ();
  3         7497  
  3         76  
125 3     3   22 use Carp ();
  3         4  
  3         40  
126 3     3   2366 use Class::C3 ();
  3         13182  
  3         590  
127              
128             our %CLASS;
129             our @ADD_FIELDS;
130              
131             sub mk_accessors {
132 7     7 1 11 my $pkg = shift;
133 7 50       19 $pkg = ref $pkg if ref $pkg;
134 7         11 my %uniq;
135 7 50       9 $CLASS{$pkg}{fields} = [ grep !$uniq{$_}++, @{ $CLASS{$pkg}{list} || [] }, @_ ];
  7         73  
136 7         37 $pkg->next::method(@_);
137             }
138              
139             sub field_list {
140 119     119 1 147 my $self = shift;
141 119   66     367 my $pkg = ref $self || $self;
142 119         103 my %uniq;
143 3   66 3   28 $CLASS{$pkg}{isa} ||= do{ no strict 'refs'; \@{$pkg.'::ISA'} };
  3         8  
  3         2312  
  119         274  
  4         5  
  4         18  
144             #warn "field_list for $self [ @{ $CLASS{$pkg}{fields} || [] } ] +from[ @{ $CLASS{$pkg}{isa} || [] } ]";
145 119 50       1038 grep !$uniq{$_}++,
146 119 100       907 map ( $_ ne $pkg && $_->can('field_list') ? $_->field_list : (), @{ $CLASS{$pkg}{isa} || [] } ),
147 119 100 66     119 @{ $CLASS{$pkg}{fields} || [] },
148             ;
149             }
150              
151             sub new {
152 10     10 1 8569 my $pkg = shift;
153 10         12 my %h;
154 10         25 TIE and tie %h, 'accessors::fast::tie', $pkg, [ $pkg->field_list,@ADD_FIELDS ];
155 10         30 my $self = bless \%h,$pkg;
156 10         32 &Hash::Util::lock_keys($self,$pkg->field_list,@ADD_FIELDS);
157 10         252 $self->init(@_);
158 10         46 return $self;
159             }
160              
161             sub init {
162 10     10 1 14 my $self = shift;
163 10 100       26 @_ or return;
164 2         3 my $args;
165             {
166 2         4 my $orig = \@_;
  2         5  
167 2         7 my $sw = $SIG{__WARN__};
168             local $SIG{__WARN__} = sub {
169 2     2   6 local $_ = shift;
170 2         16 local *__ANON__ = 'init:SIG:WARN';
171 2 50       354 return unless warnings::enabled( $ME );
172 0 0       0 if(m{Odd number of elements}s) {
173 0 0       0 @_ = ("Wrong init params for $self: [ ".join(', ', map { defined() ? length() ? $_ : "''" : 'undef' } @$orig)." ]. Pass a single hash ref");
  0 0       0  
174 0 0       0 local $SIG{__WARN__} = $sw if $sw;
175 0         0 Carp::carp(@_);
176 0         0 return;
177             }
178 0 0       0 goto &$sw if $sw;
179 0         0 CORE::warn $_;
180 2         13 };
181 2 50 33     31 $args = ( @_ == 1 && ref $_[0] ) ? shift : +{ @_ };
182             }
183             #warn "$self\->init (@{[ %$args ]})";
184             #warn "$self\->init $args";
185 2         8 my %chk = map { $_ => 1 } $self->field_list;
  8         17  
186             #warn "$self have fields @{[ $self->field_list ]}";
187 2         9 for (keys %$args) {
188 4 50       383 if ($chk{$_}){
    50          
189 0         0 $self->{$_} = $args->{$_};
190             }
191             elsif(warnings::enabled( $ME )){
192 0         0 my ($file,$line) = (caller(1))[1,2];
193 0         0 warn "class `".(ref $self)."' have no field `$_' but instance attempted ".
194             "to be initialized with value '$args->{$_}' at $file line $line.\n";
195             }
196             }
197 2         7 return;
198             }
199              
200             sub import {
201 3     3   20 no strict 'refs';
  3         16  
  3         980  
202 7 50   7   1754 ( my $me = shift ) eq $ME or return; # Only me can define class isa.
203 7         16 my $pkg = caller;
204             #warn "declare $pkg as $me at @{[ (caller(0))[1,2] ]}";
205 7 100       86 push @{$pkg.'::ISA'}, $me unless $pkg->isa($me);
  5         76  
206 7         17 $CLASS{$pkg}{isa} = \@{$pkg.'::ISA'};
  7         29  
207 7         46 $pkg->mk_accessors(@_);
208             }
209              
210             1;
211             __END__