File Coverage

blib/lib/Coat/Object.pm
Criterion Covered Total %
statement 63 82 76.8
branch 13 24 54.1
condition 14 15 93.3
subroutine 13 15 86.6
pod 3 7 42.8
total 106 143 74.1


line stmt bran cond sub pod time code
1             package Coat::Object;
2              
3 43     43   234 use strict;
  43         78  
  43         1615  
4 43     43   212 use warnings;
  43         78  
  43         1109  
5 43     43   209 use Coat::Meta;
  43         75  
  43         890  
6 43     43   211 use Carp 'confess';
  43         64  
  43         8865  
7              
8             # this is the mother-class of each Coat objects, it provides
9             # basic instance methods such as a constructor
10              
11             # The default constructor
12             sub new {
13 112     112 1 29281 my ( $class, @args ) = @_;
14              
15             # create the newborn
16 112         365 my $self = {};
17 112         258 bless $self, $class;
18              
19             # parse and prepare the args
20 112         581 my $args = $self->build_args(@args);
21              
22             # init the object
23 112         703 $self->init($args);
24              
25             # done
26 105         456 return $self;
27             }
28              
29             sub build_args {
30 112     112 0 248 my ($self, @args) = @_;
31 112         196 my $class = ref($self);
32              
33 112         139 my $args;
34 112 50       562 $args = {@args} if @args % 2 == 0;
35              
36             # if BUILDARGS exists, look or it and run it
37 112 50       962 if ($self->can('BUILDARGS')) {
38 0         0 foreach my $pkg (reverse Coat::Meta->linearized_isa($class)) {
39 0         0 my $buildargs_sub;
40             {
41 43     43   314 no strict 'refs';
  43         145  
  43         26911  
  0         0  
42 0         0 $buildargs_sub = *{$pkg."::BUILDARGS"};
  0         0  
43             }
44 0 0       0 if (defined &$buildargs_sub) {
45 0         0 $args = $self->$buildargs_sub(@args);
46 0         0 last;
47             }
48             }
49             }
50              
51             # now check everything is OK with the args
52 112 50       297 unless (defined $args) {
53 0 0       0 if (@args == 1) {
54 0 0       0 if (ref($args[0]) ne 'HASHREF') {
55 0         0 confess "Single argument must be an HASHREF";
56             }
57             else {
58 0         0 $args = $args[0];
59             }
60             }
61             else {
62 0         0 confess "Invalid arguments";
63             }
64             }
65 112         269 return $args;
66             }
67              
68             # returns the meta-class description of that instance
69             sub meta {
70 0     0 1 0 my ($self) = @_;
71 0         0 return Coat::Meta->class( ref($self) );
72             }
73              
74             # init an instance : put default values and set values
75             # given at instanciation time
76             sub init {
77 112     112 1 193 my ( $self, $attrs ) = @_;
78 112         376 my $class = ref $self;
79              
80 112         484 my $class_attr = Coat::Meta->all_attributes( $class );
81            
82             # setting all default values
83 112         168 foreach my $attr ( keys %{$class_attr} ) {
  112         342  
84 240         392 my $meta = $class_attr->{$attr};
85              
86 240 100 100     970 confess "You cannot have lazy attribute ($attr) without specifying a default value for it"
87             if ($meta->{lazy} && !exists($meta->{default}));
88              
89             # handling default values for non-lazy slots
90 239 100 100     1230 if ( (! $meta->{'lazy'}) && defined $meta->{'default'} ) {
91              
92             # saving original permission and setting it to read/write
93 46         95 my $is = $meta->{'is'};
94 46         117 $meta->{'is'} = 'rw';
95            
96             # set default value
97 46         182 $self->$attr( Coat::Meta->attr_default( $self, $attr) );
98              
99             # restoring original permissions
100 46         107 $meta->{'is'} = $is;
101             }
102            
103             # a required read-only field must have a default value or be set at
104             # instanciation time
105 239 100 100     1242 confess "Attribute ($attr) is required"
      66        
      100        
106             if ($meta->{'required'} &&
107             $meta->{'is'} eq 'ro' &&
108             (! exists $meta->{'default'}) &&
109             (! exists $attrs->{$attr}));
110             }
111              
112             # setting values given at instanciation time
113 109         391 foreach my $attr ( keys %$attrs ) {
114 38         87 my $is = $class_attr->{$attr}{'is'};
115            
116 38         79 $class_attr->{$attr}{'is'} = 'rw';
117 38         156 $self->$attr( $attrs->{$attr} );
118 34         113 $class_attr->{$attr}{'is'} = $is;
119             }
120              
121 105         621 $self->BUILDALL($attrs);
122 105         265 return $self;
123             }
124              
125             # This is done to let us implement easily the BUILDARGS/BUILD/DEMOLISH stuff
126             # It must behave the same: with inheritance in mind.
127             # Thanks again to the Moose team for the idea of *ALL() methods.
128              
129             sub _run_for_all {
130 217     217   403 my ($method_name, $self, $params) = @_;
131 217         352 my $class = ref($self);
132              
133 217 100       5069 return unless $self->can($method_name);
134              
135 5         8 my $sub;
136 5         40 foreach my $pkg (reverse Coat::Meta->linearized_isa($class)) {
137             {
138 43     43   245 no strict 'refs';
  43         84  
  43         9778  
  12         14  
139 12         13 $sub = *{$pkg."::${method_name}"};
  12         68  
140             }
141 12 100       70 $self->$sub( %$params ) if defined &$sub;
142             }
143             }
144              
145 105     105 0 309 sub BUILDALL { _run_for_all('BUILD', @_) }
146              
147 112     112 0 356 sub DEMOLISHALL { _run_for_all('DEMOLISH', @_) }
148              
149 112     112   50921 sub DESTROY { goto &DEMOLISHALL }
150              
151             # taken from Moose::Object
152             sub dump {
153 0     0 0   my $self = shift;
154 0           require Data::Dumper;
155 0 0         local $Data::Dumper::Maxdepth = shift if @_;
156 0           Data::Dumper::Dumper $self;
157             }
158              
159             # end Coat::Object
160             1;
161             __END__