File Coverage

blib/lib/Simple/Accessor.pm
Criterion Covered Total %
statement 55 57 96.4
branch 20 26 76.9
condition n/a
subroutine 9 9 100.0
pod n/a
total 84 92 91.3


line stmt bran cond sub pod time code
1             package Simple::Accessor;
2             $Simple::Accessor::VERSION = '1.11';
3 1     1   695 use strict;
  1         1  
  1         22  
4 1     1   3 use warnings;
  1         1  
  1         94  
5              
6             # ABSTRACT: a light and simple way to provide accessor in perl
7              
8             =head1 NAME
9             Simple::Accessor - very simple, light and powerful accessor
10              
11             =head1 VERSION
12              
13             version 1.11
14              
15             =head1 DESCRIPTION
16              
17             Simple::Accessor provides a simple object layer without any dependency.
18             It can be used where other ORM could be considered too heavy.
19             But it has also the main advantage to only need one single line of code.
20              
21             It can be easily used in scripts...
22              
23             =head1 Usage
24              
25             Create a package and just call Simple::Accessor.
26             The new method will be imported for you, and all accessors will be directly
27             accessible.
28              
29             package MyClass;
30              
31             # that s all what you need ! no more line required
32             use Simple::Accessor qw{foo bar cherry apple};
33              
34             You can now call 'new' on your class, and create objects using these attributes
35            
36             package main;
37             use MyClass;
38              
39             my $o = MyClass->new()
40             or MyClass->new(bar => 42)
41             or MyClass->new(apple => 'fruit', cherry => 'fruit', banana => 'yummy');
42              
43             You can get / set any value using the accessor
44            
45             is $o->bar(), 42;
46             $o->bar(51);
47             is $o->bar(), 51;
48            
49             You can provide your own init method that will be call by new with default args.
50             This is optional.
51              
52             package MyClass;
53              
54             sub build { # previously known as initialize
55             my ($self, %opts) = @_;
56            
57             $self->foo(12345);
58             }
59              
60             You can also control the object after or before its creation using
61              
62             sub _before_build {
63             my ($self, %opts) = @_;
64             ...
65             }
66              
67             sub _after_build {
68             my ($self, %opts) = @_;
69             ...
70             bless $self, 'Basket';
71             }
72              
73             You can also provide individual builders / initializers
74              
75             sub _build_bar { # previously known as _initialize_bar
76             # will be used if no value has been provided for bar
77             1031;
78             }
79              
80             sub _build_cherry {
81             'red';
82             }
83              
84             You can even use a very basic but useful hook system.
85             Any false value return by before or validate, will stop the setting process.
86             Be careful with the after method, as there is no protection against infinite loop.
87              
88             sub _before_foo {
89             my ($self, $v) = @_;
90            
91             # do whatever you want with $v
92             return 1 or 0;
93             }
94              
95             sub _validate_foo {
96             my ($self, $v) = @_;
97             # invalid value ( will not be set )
98             return 0 if ( $v == 42);
99             # valid value
100             return 1;
101             }
102              
103             sub _after_cherry {
104             my ($self) = @_;
105            
106             # use the set value for extra operations
107             $self->apple($self->cherry());
108             }
109            
110             =head1 METHODS
111              
112             None. The only public method provided is the classical import.
113              
114             =cut
115              
116             sub import {
117 3     3   1109 my ( $class, @attr ) = @_;
118              
119 3         5 my $from = caller();
120              
121 3         3 _add_new($from);
122 3         5 _add_accessors( to => $from, attributes => \@attr );
123             }
124              
125             sub _add_new {
126 3     3   3 my $class = shift;
127 3 50       6 return unless $class;
128              
129 3         5 my $new = $class . '::new';
130             {
131 1     1   3 no strict 'refs';
  1         1  
  1         182  
  3         3  
132             *$new = sub {
133 8     8   954 my ( $class, %opts ) = @_;
134              
135 8         13 my $self = bless {}, $class;
136              
137             # set values if attributes exist
138             map {
139 8         13 eval { $self->$_( $opts{$_} ) }
  3         11  
  3         15  
140             } keys %opts;
141              
142 8 50       34 if ( $self->can( '_before_build') ) {
143 0         0 $self->_before_build( %opts );
144             }
145              
146 8         9 foreach my $init ( 'build', 'initialize' ) {
147 16 100       36 if ( $self->can( $init ) ) {
148 4 50       47 return unless $self->$init(%opts);
149             }
150             }
151              
152 8 50       36 if ( $self->can( '_after_build') ) {
153 0         0 $self->_after_build( %opts );
154             }
155              
156 8         13 return $self;
157 3         19 };
158             }
159             }
160              
161             sub _add_accessors {
162 3     3   6 my (%opts) = @_;
163              
164 3 50       5 return unless $opts{to};
165 3         3 my @attributes = @{ $opts{attributes} };
  3         5  
166 3 50       7 return unless @attributes;
167              
168 3         4 foreach my $att (@attributes) {
169 10         10 my $accessor = $opts{to} . "::$att";
170              
171             # allow symbolic refs to typeglob
172 1     1   3 no strict 'refs';
  1         1  
  1         153  
173             *$accessor = sub {
174 34     34   1244 my ( $self, $v ) = @_;
175 34 100       73 if ( defined $v ) {
    100          
176 15         20 foreach (qw{before validate set after}) {
177 58 100       73 if ( $_ eq 'set' ) {
178 14         20 $self->{$att} = $v;
179 14         14 next;
180             }
181 44         48 my $sub = '_' . $_ . '_' . $att;
182 44 100       167 if ( $self->can( $sub ) ) {
183 4 100       9 return unless $self->$sub($v);
184             }
185             }
186             }
187             elsif ( !defined $self->{$att} ) {
188             # try to initialize the value (try first with build)
189             # initialize is here for backward compatibility with older versions
190 7         7 foreach my $builder ( qw{build initialize} ) {
191 14         18 my $sub = '_' . $builder . '_' . $att;
192 14 100       51 if ( $self->can( $sub ) ) {
193 1         3 return $self->{$att} = $self->$sub();
194             }
195             }
196             }
197              
198 32         77 return $self->{$att};
199 10         39 };
200             }
201 3         187 @attributes = ();
202             }
203              
204             1;
205              
206             =head1 CONTRIBUTE
207              
208             You can contribute to this project on github https://github.com/atoomic/Simple-Accessor
209              
210             =cut
211              
212             __END__