File Coverage

blib/lib/Method/Generate/Accessor/Role/Monjon.pm
Criterion Covered Total %
statement 75 86 87.2
branch 10 10 100.0
condition 5 12 41.6
subroutine 18 22 81.8
pod 0 2 0.0
total 108 132 81.8


line stmt bran cond sub pod time code
1 2     2   34889 use 5.006;
  2         6  
  2         77  
2 2     2   11 use strict;
  2         4  
  2         75  
3 2     2   12 use warnings;
  2         3  
  2         56  
4              
5 2     2   19 use List::Util ();
  2         10  
  2         30  
6 2     2   23 use Sub::Quote ();
  2         8  
  2         136  
7              
8             package Method::Generate::Accessor::Role::Monjon;
9              
10             our $AUTHORITY = 'cpan:TOBYINK';
11             our $VERSION = '0.003';
12              
13 2     2   10 use Moo::Role;
  2         4  
  2         14  
14              
15             my $_fh;
16             BEGIN {
17 2   33 2   1089 $_fh ||= eval { require Hash::FieldHash; \&Hash::FieldHash::fieldhashes };
  2         1566  
  2         1396  
18 2   33     9 $_fh ||= eval { require Hash::Util::FieldHash::Compat; \&Hash::Util::FieldHash::Compat::fieldhash };
  0         0  
  0         0  
19 2   33     430 $_fh ||= do { require Hash::Util::FieldHash; \&Hash::Util::FieldHash::fieldhash };
  0         0  
  0         0  
20             };
21              
22             $_fh->(\(our %FIELDS));
23             $_fh->(\(my %INV_MAKERS));
24              
25             sub target_class
26             {
27 18     18 0 25 my $self = shift;
28 18 100       75 if (not defined $INV_MAKERS{$self})
29             {
30 3         13 for my $class (keys %Moo::MAKERS)
31             {
32 11 100       33 next unless defined $Moo::MAKERS{$class}{accessor};
33 8 100       38 next unless $self == $Moo::MAKERS{$class}{accessor};
34 3         15 return( $INV_MAKERS{$self} = $class );
35             }
36             }
37 15         51 return $INV_MAKERS{$self};
38             }
39              
40             my $order = 0;
41             sub _monjon_canonicalize
42             {
43 10     10   14 my $self = shift;
44 10         21 my ($me, $name, $spec) = @_;
45            
46 10         28 $spec->{_order} =++ $order;
47            
48             # TODO
49             }
50              
51             around generate_method => sub
52             {
53             my $next = shift;
54             my $self = shift;
55             $self->_monjon_canonicalize(@_);
56 2     2   11 no warnings qw(once);
  2         3  
  2         1923  
57             local $Method::Generate::Accessor::CAN_HAZ_XS = 0;
58             $self->$next(@_);
59             };
60              
61             my $P = __PACKAGE__ . "::";
62              
63             sub _generate_simple_has
64             {
65 1     1   2 my $self = shift;
66 1         2 my ($me, $name, $spec) = @_;
67 1         3 my $name_str = quotemeta($name);
68 1         17 "exists(\$${P}FIELDS{${me}}{\"${name_str}\"})";
69             }
70              
71             sub _generate_simple_clear
72             {
73 0     0   0 my $self = shift;
74 0         0 my ($me, $name, $spec) = @_;
75 0         0 my $name_str = quotemeta($name);
76 0         0 "delete(\$${P}FIELDS{${me}}{\"${name_str}\"})";
77             }
78              
79             sub _generate_simple_get
80             {
81 1     1   2 my $self = shift;
82 1         3 my ($me, $name, $spec) = @_;
83 1         3 my $name_str = quotemeta($name);
84 1         7 "\$${P}FIELDS{${me}}{\"${name_str}\"}";
85             }
86              
87             sub _generate_core_set
88             {
89 2     2   4 my $self = shift;
90 2         6 my ($me, $name, $spec, $value) = @_;
91 2         5 my $name_str = quotemeta($name);
92 2         14 "\$${P}FIELDS{${me}}{\"${name_str}\"} = ${value}";
93             }
94              
95             sub _generate_xs
96             {
97 0     0   0 die "Can't generate XS accessors for Monjon accessors";
98             }
99              
100             sub default_construction_string
101             {
102 2     2 0 537 my $self = shift;
103            
104 2         9 my $ctor = 'Monjon'->_constructor_maker_for($self->target_class);
105 2         21 my $all = $ctor->all_attribute_specs;
106 3         11 my $total = List::Util::sum(
107             0,
108             map {
109 2         13 $self->_calculate_length(undef, $_, $all->{$_})
110             } $ctor->monjon_fields,
111             );
112            
113 2         66 sprintf(
114             '\(my $s = "\0" x %d)',
115             $total,
116             );
117             }
118              
119             my @generators = qw(
120             _generate_simple_has
121             _generate_simple_clear
122             _generate_simple_get
123             _generate_core_set
124             );
125             for my $method (@generators)
126             {
127             my $packed_generator = "$method\_packed";
128             around $method => sub {
129             my $next = shift;
130             my $self = shift;
131             my ($me, $name, $spec) = @_;
132             exists($spec->{pack})
133             ? $self->$packed_generator(@_)
134             : $self->$next(@_);
135             };
136             }
137              
138             sub _generate_simple_has_packed
139             {
140 0     0   0 return '(1)';
141             }
142              
143             sub _generate_simple_clear_packed
144             {
145 0     0   0 die "This attribute cannot have a clearer; bailing out";
146             }
147              
148             sub _generate_simple_get_packed
149             {
150 9     9   17 my $self = shift;
151 9         12 my ($me, $name, $spec) = @_;
152 9         50 sprintf(
153             'unpack(q(%s), substr(${%s}, %d, %d))',
154             $spec->{pack},
155             $me,
156             $self->_calculate_offset(@_),
157             $self->_calculate_length(@_),
158             );
159             }
160              
161             sub _generate_core_set_packed
162             {
163 7     7   13 my $self = shift;
164 7         14 my ($me, $name, $spec, $value) = @_;
165 7         23 sprintf(
166             'substr(${%s}, %d, %d) = pack(q(%s), %s)',
167             $me,
168             $self->_calculate_offset(@_),
169             $self->_calculate_length(@_),
170             $spec->{pack},
171             $value,
172             );
173             }
174              
175             sub _calculate_offset
176             {
177 16     16   23 my $self = shift;
178 16         26 my ($me, $name, $spec) = @_;
179 16         50 my $target = $self->target_class;
180            
181 16 100       67 if (not defined $spec->{_pack_offset}{$target})
182             {
183 5         40 my $ctor = 'Monjon'->_constructor_maker_for($target);
184 5         60 my $all = $ctor->all_attribute_specs;
185            
186 5         23 my $offset = 0;
187 5         30 for my $field ( $ctor->monjon_fields )
188             {
189 7 100       20 last if $field eq $name;
190 2         13 $offset += $self->_calculate_length($me, $field, $all->{$field});
191             }
192 5         15 $spec->{_pack_offset}{$target} = $offset;
193             }
194            
195 16         560 $spec->{_pack_offset}{$target};
196             }
197              
198             sub _calculate_length
199             {
200 21     21   45 my $self = shift;
201 21         31 my ($me, $name, $spec) = @_;
202 21   66     296 $spec->{_pack_length} ||= length pack($spec->{pack}, 0);
203             }
204              
205             1;