File Coverage

blib/lib/JIP/ClassField.pm
Criterion Covered Total %
statement 88 88 100.0
branch 26 26 100.0
condition 8 9 88.8
subroutine 44 44 100.0
pod 0 3 0.0
total 166 170 97.6


line stmt bran cond sub pod time code
1             package JIP::ClassField;
2              
3 1     1   73424 use 5.006;
  1         3  
4 1     1   6 use strict;
  1         1  
  1         20  
5 1     1   4 use warnings;
  1         2  
  1         29  
6 1     1   6 use Carp qw(croak);
  1         2  
  1         62  
7 1     1   8 use English qw(-no_match_vars);
  1         1  
  1         5  
8              
9             our $VERSION = '0.051';
10              
11             my $maybe_set_subname = sub { $ARG[1]; };
12              
13             # Supported on Perl 5.22+
14             eval {
15             require Sub::Util;
16              
17             if (my $set_subname = Sub::Util->can('set_subname')) {
18             $maybe_set_subname = $set_subname;
19             }
20             };
21              
22             sub attr {
23 17     17 0 6595 my ($self, $attr, %param) = @ARG;
24              
25 17   66     67 my $class = ref $self || $self;
26              
27 17 100 100     313 croak q{Class not defined}
28             unless defined $class && length $class;
29              
30 15 100 100     208 croak q{Attribute not defined}
31             unless defined $attr && length $attr;
32              
33 13         20 my @patches;
34              
35 13 100       17 for my $each_attr (@{ ref $attr eq 'ARRAY' ? $attr : [$attr] }) {
  13         52  
36 14 100       151 croak sprintf(q{Attribute "%s" invalid}, $each_attr)
37             unless $each_attr =~ m{^[a-zA-Z_]\w*$}x;
38              
39 13         19 my %patch;
40              
41             $patch{_define_name_of_getter($each_attr, \%param)} = sub {
42 11     11   26 my $self = shift;
        11      
        11      
        11      
        11      
        11      
        11      
        11      
        11      
        11      
        11      
        11      
        11      
43 11         41 return $self->{$each_attr};
44 13         48 };
45              
46             {
47 13         24 my $method_name = _define_name_of_setter($each_attr, \%param);
  13         24  
48              
49 13 100       29 if (exists $param{'default'}) {
50 2         4 my $default_value = $param{'default'};
51              
52             $patch{$method_name} = sub {
53 6     6   5514 my $self = shift;
        6      
        6      
54              
55 6 100       17 if (@ARG == 1) {
56 3         7 $self->{$each_attr} = shift;
57             }
58             else {
59 3 100       13 $self->{$each_attr} = ref($default_value) eq 'CODE' ?
60             $default_value->($self) : $default_value;
61             }
62              
63 6         19 return $self;
64 2         8 };
65             }
66             else {
67             $patch{$method_name} = sub {
68 5     5   8197 my ($self, $value) = @ARG;
        5      
        5      
        5      
        5      
        5      
        5      
        5      
        5      
        5      
        5      
69 5         22 $self->{$each_attr} = $value;
70 5         14 return $self;
71 11         44 };
72             }
73             }
74              
75 13         30 push @patches, \%patch;
76             }
77              
78 12         27 monkey_patch($class, %{ $_ }) for @patches;
  13         37  
79             }
80              
81             sub monkey_patch {
82 15     15 0 39 my ($class, %patch) = @ARG;
83              
84 1     1   861 no strict 'refs';
  1         3  
  1         44  
85 1     1   6 no warnings 'redefine';
  1         2  
  1         121  
86              
87 15         49 while (my ($method_name, $value) = each %patch) {
88 28         57 my $full_name = $class .q{::}. $method_name;
89              
90 28         110 *{$full_name} = $maybe_set_subname->($full_name, $value);
  28         157  
91             }
92              
93 15         99 return 1;
94             }
95              
96             sub cleanup_namespace {
97 1     1 0 413 my @names = @ARG;
98 1         3 my $caller = caller;
99              
100 1     1   8 no strict 'refs';
  1         2  
  1         322  
101 1         2 my $ref = \%{ $caller .'::' };
  1         4  
102              
103 1         3 map { delete $ref->{$_} } @names;
  2         13  
104              
105 1         4 return 1;
106             }
107              
108             sub import {
109 2     2   2617 my $caller = caller;
110              
111 2     3   10 return monkey_patch($caller, 'has', sub { attr($caller, @ARG) });
  3     3   6636  
        3      
112             }
113              
114             sub _define_name_of_getter {
115 17     17   2573 my ($attr, $param) = @ARG;
116              
117 17         26 my $method_name;
118              
119 17 100       32 if (exists $param->{'get'}) {
120 15         25 my $getter = $param->{'get'};
121              
122 15 100       32 if ($getter eq q{+}) {
    100          
123 10         15 $method_name = $attr;
124             }
125             elsif ($getter eq q{-}) {
126 3         7 $method_name = q{_}. $attr;
127             }
128             else {
129 2         4 $method_name = $getter;
130             }
131             }
132             else {
133 2         5 $method_name = $attr;
134             }
135              
136 17         53 return $method_name;
137             }
138              
139             sub _define_name_of_setter {
140 17     17   2769 my ($attr, $param) = @ARG;
141              
142 17         24 my $method_name;
143              
144 17 100       30 if (exists $param->{'set'}) {
145 15         23 my $setter = $param->{'set'};
146              
147 15 100       32 if ($setter eq q{+}) {
    100          
148 10         20 $method_name = q{set_}. $attr;
149             }
150             elsif ($setter eq q{-}) {
151 3         7 $method_name = q{_set_}. $attr;
152             }
153             else {
154 2         4 $method_name = $setter;
155             }
156             }
157             else {
158 2         5 $method_name = q{set_}. $attr;
159             }
160              
161 17         40 return $method_name;
162             }
163              
164             1;
165              
166             __END__