File Coverage

blib/lib/Simple/Accessor.pm
Criterion Covered Total %
statement 60 62 96.7
branch 20 26 76.9
condition n/a
subroutine 9 9 100.0
pod n/a
total 89 97 91.7


line stmt bran cond sub pod time code
1             package Simple::Accessor;
2             $Simple::Accessor::VERSION = '1.10';
3 1     1   759 use strict;
  1         1  
  1         22  
4 1     1   4 use warnings;
  1         1  
  1         98  
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.10
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   1395 my ( $class, @attr ) = @_;
118              
119 3         5 my $from = caller();
120              
121 3         5 _add_new($from);
122 3         18 _add_accessors( to => $from, attributes => \@attr );
123             }
124              
125             sub _add_new {
126 3     3   3 my $class = shift;
127 3 50       8 return unless $class;
128              
129 3         4 my $new = $class . '::new';
130             {
131 1     1   3 no strict 'refs';
  1         1  
  1         189  
  3         3  
132             *$new = sub {
133 8     8   1634 my ( $class, %opts ) = @_;
134              
135 8         10 my $self = bless {}, $class;
136              
137             # set values if attributes exist
138             map {
139 8         13 eval { $self->$_( $opts{$_} ) }
  3         4  
  3         16  
140             } keys %opts;
141              
142 8 50       5 if ( defined &{ $class . '::_before_build' } ) {
  8         39  
143 0         0 $self->_before_build( %opts );
144             }
145              
146 8         10 foreach my $init ( 'build', 'initialize' ) {
147 16 100       10 if ( defined &{ $class . '::' . $init } ) {
  16         41  
148 4 50       9 return unless $self->$init(%opts);
149             }
150             }
151              
152 8 50       22 if ( defined &{ $class . '::_after_build' } ) {
  8         22  
153 0         0 $self->_after_build( %opts );
154             }
155              
156 8         15 return $self;
157 3         21 };
158             }
159             }
160              
161             sub _add_accessors {
162 3     3   7 my (%opts) = @_;
163              
164 3 50       6 return unless $opts{to};
165 3         2 my @attributes = @{ $opts{attributes} };
  3         6  
166 3 50       7 return unless @attributes;
167              
168 3         4 foreach my $att (@attributes) {
169 10         11 my $accessor = $opts{to} . "::$att";
170              
171             # allow symbolic refs to typeglob
172 1     1   4 no strict 'refs';
  1         1  
  1         193  
173             *$accessor = sub {
174 34     34   1745 my ( $self, $v ) = @_;
175 34 100       78 if ( defined $v ) {
    100          
176 15         19 foreach (qw{before validate set after}) {
177 58 100       78 if ( $_ eq 'set' ) {
178 14         18 $self->{$att} = $v;
179 14         22 next;
180             }
181 44         46 my $sub = '_' . $_ . '_' . $att;
182 44 100       29 if ( defined &{ $opts{to} . '::' . $sub } ) {
  44         141  
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         19 my $sub = '_' . $builder . '_' . $att;
192 14 100       7 if ( defined &{ $opts{to} . '::' . $sub } ) {
  14         56  
193 1         3 return $self->{$att} = $self->$sub();
194             }
195             }
196             }
197              
198 32         88 return $self->{$att};
199 10         42 };
200             }
201 3         175 @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__