File Coverage

blib/lib/JIP/Object.pm
Criterion Covered Total %
statement 104 104 100.0
branch 42 44 95.4
condition 8 8 100.0
subroutine 28 29 96.5
pod 6 10 60.0
total 188 195 96.4


line stmt bran cond sub pod time code
1             package JIP::Object;
2              
3 1     1   2065 use 5.006;
  1         3  
4 1     1   4 use strict;
  1         2  
  1         19  
5 1     1   13 use warnings;
  1         1  
  1         34  
6 1     1   4 use Carp qw(croak);
  1         2  
  1         63  
7 1     1   5 use Scalar::Util qw(blessed);
  1         1  
  1         77  
8 1     1   4 use English qw(-no_match_vars);
  1         2  
  1         7  
9              
10             our $VERSION = '0.02';
11             our $AUTOLOAD;
12              
13             my $maybe_set_subname = sub { $ARG[1]; };
14              
15             # Will be shipping with Perl 5.22
16             eval {
17             require Sub::Util;
18              
19             if (my $set_subname = Sub::Util->can('set_subname')) {
20             $maybe_set_subname = $set_subname;
21             }
22             };
23              
24             sub new {
25 13     13 1 8813 my ($class, %param) = @ARG;
26              
27 13 100       273 croak q{Class already blessed} if blessed $class;
28              
29 12         17 my $proto;
30 12 100       35 if (exists $param{'proto'}) {
31 3         8 $proto = $param{'proto'};
32              
33 3 100 100     223 croak q{Bad argument "proto"}
34             unless (blessed $proto || q{}) eq __PACKAGE__;
35             }
36              
37 11         44 return bless({}, $class)
38             ->_set_stash({})
39             ->_set_meta({})
40             ->set_proto($proto);
41             }
42              
43             sub has {
44 11     11 1 3222 my ($self, $attr, %param) = @ARG;
45              
46 11 100       175 croak q{Can't call "has" as a class method} unless blessed $self;
47              
48 10 100 100     207 croak q{Attribute not defined} unless defined $attr and length $attr;
49              
50 8 50       19 if (exists $param{'get'}) {
51 8         18 my ($method_name, $getter) = (q{}, $param{'get'});
52              
53 8 100       22 if ($getter eq q{+}) {
    100          
54 5         8 $method_name = $attr;
55             }
56             elsif ($getter eq q{-}) {
57 2         3 $method_name = q{_}. $attr;
58             }
59             else {
60 1         2 $method_name = $getter;
61             }
62              
63             $self->_meta->{$method_name} = $maybe_set_subname->($method_name, sub {
64 13     13   21 my $self = shift;
65 13         30 return $self->_stash->{$attr};
66 8         75 });
67             }
68              
69 8 50       38 if (exists $param{'set'}) {
70 8         17 my ($method_name, $setter) = (q{}, $param{'set'});
71              
72 8 100       231 if ($setter eq q{+}) {
    100          
73 5         10 $method_name = q{set_}. $attr;
74             }
75             elsif ($setter eq q{-}) {
76 2         4 $method_name = q{_set_}. $attr;
77             }
78             else {
79 1         1 $method_name = $setter;
80             }
81              
82 8 100       16 if (exists $param{'default'}) {
83 2         3 my $default_value = $param{'default'};
84              
85             $self->_meta->{$method_name} = $maybe_set_subname->($method_name, sub {
86 6     6   16 my $self = shift;
87              
88 6 100       27 if (@ARG == 1) {
    100          
89 4         275 $self->_stash->{$attr} = shift;
90             }
91             elsif (ref $default_value eq 'CODE') {
92 1         9 $self->_stash->{$attr} = $maybe_set_subname->(
93             'default_value',
94             $default_value,
95             )->($self);
96             }
97             else {
98 1         6 $self->_stash->{$attr} = $default_value;
99             }
100              
101 6         65 return $self;
102 2         18 });
103             }
104             else {
105             $self->_meta->{$method_name} = $maybe_set_subname->($method_name, sub {
106 6     6   11 my ($self, $value) = @ARG;
107 6         14 $self->_stash->{$attr} = $value;
108 6         36 return $self;
109 6         40 });
110             }
111             }
112              
113 8         71 return $self;
114             }
115              
116             sub method {
117 9     9 1 3401 my ($self, $method_name, $code) = @ARG;
118              
119 9 100       209 croak q{Can't call "method" as a class method}
120             unless blessed $self;
121              
122 8 100 100     188 croak q{First argument must be a non empty string}
123             unless defined $method_name and length $method_name;
124              
125 6 100       84 croak q{Second argument must be a code ref}
126             unless ref($code) eq 'CODE';
127              
128 5         30 $self->_meta->{$method_name} = $maybe_set_subname->($method_name, $code);
129              
130 5         17 return $self;
131             }
132              
133             sub own_method {
134 45     45 1 91 my ($self, $method_name) = @ARG;
135              
136 45 100       91 return unless exists $self->_meta->{$method_name};
137              
138 35         289 return $self->_meta->{$method_name};
139             }
140              
141             # http://perldoc.perl.org/perlobj.html#Default-UNIVERSAL-methods
142             sub isa {
143 1     1   1196 no warnings 'misc';
  1         2  
  1         78  
144 10     10 0 186 goto &UNIVERSAL::isa;
145             }
146              
147             sub DOES {
148             # DOES is equivalent to isa by default
149 3     3 0 9 goto &isa;
150             }
151              
152             sub VERSION {
153 1     1   5 no warnings 'misc';
  1         1  
  1         62  
154 3     3 0 1794 goto &UNIVERSAL::VERSION;
155             }
156              
157             sub can {
158 15     15 0 2425 my ($self, $method_name) = @ARG;
159              
160 15 100       74 if (blessed $self) {
161 1     1   4 no warnings 'misc';
  1         2  
  1         46  
162 8         172 goto &UNIVERSAL::can;
163             }
164             else {
165 7         15 my $code;
166 1     1   5 no warnings 'misc';
  1         2  
  1         392  
167 7         42 $code = UNIVERSAL::can($self, $method_name);
168              
169 7         39 return $code;
170             }
171             }
172              
173       0     sub DESTROY {}
174              
175             sub AUTOLOAD {
176 38     38   5722 my ($self) = @ARG;
177              
178 38 100       263 croak q{Can't call "AUTOLOAD" as a class method} unless blessed $self;
179              
180 37         211 my ($package, $method_name) = ($AUTOLOAD =~ m{^(.+)::([^:]+)$}x);
181 37         55 undef $AUTOLOAD;
182              
183 37 100       320 if (defined(my $code = $self->own_method($method_name))) {
    100          
184 32         151 goto &$code;
185             }
186             elsif (defined(my $proto = $self->proto)) {
187 4         5 shift @ARG;
188 4         18 $proto->$method_name(@ARG);
189             }
190             else {
191 1         84 croak(sprintf q{Can't locate object method "%s" in this instance}, $method_name);
192             }
193             }
194              
195             # private methods
196             sub proto {
197 9     9 1 777 return $ARG[0]->{'proto'};
198             }
199             sub set_proto {
200 12     12 1 26 $ARG[0]->{'proto'} = $ARG[1];
201 12         46 return $ARG[0];
202             }
203              
204             sub _meta {
205 101     101   968 return $ARG[0]->{'meta'};
206             }
207             sub _set_meta {
208 11     11   22 $ARG[0]->{'meta'} = $ARG[1];
209 11         33 return $ARG[0];
210             }
211              
212             sub _stash {
213 25     25   113 return $ARG[0]->{'stash'};
214             }
215             sub _set_stash {
216 11     11   38 $ARG[0]->{'stash'} = $ARG[1];
217 11         38 return $ARG[0];
218             }
219              
220             1;
221              
222             __END__