File Coverage

blib/lib/Mite/Attribute.pm
Criterion Covered Total %
statement 393 549 71.5
branch 180 296 60.8
condition 97 180 53.8
subroutine 55 62 88.7
pod 0 14 0.0
total 725 1101 65.8


line stmt bran cond sub pod time code
1 79     79   6853102 use 5.010001;
  79         510  
2 79     79   676 use strict;
  79         198  
  79         1932  
3 79     79   485 use warnings;
  79         277  
  79         3711  
4              
5             package Mite::Attribute;
6 79     79   11874 use Mite::Miteception qw( -all !lazy );
  79         228  
  79         862  
7              
8             our $AUTHORITY = 'cpan:TOBYINK';
9             our $VERSION = '0.012000';
10              
11 79     79   693 use B ();
  79         629  
  79         1334  
12 79     79   535 use List::Util ();
  79         267  
  79         69785  
13              
14             my $order = 0;
15             has _order =>
16             is => rw,
17             init_arg => undef,
18 174     174   955 builder => sub { $order++ };
19              
20             has definition_context =>
21             is => rw,
22             isa => HashRef,
23             default => \ '{}';
24              
25             has class =>
26             is => rw,
27             isa => MitePackage,
28             weak_ref => true;
29              
30             has compiling_class =>
31             init_arg => undef,
32             is => rw,
33             isa => MitePackage,
34             local_writer => true;
35              
36             has _class_for_default =>
37             is => rw,
38             isa => MitePackage,
39             weak_ref => true,
40             lazy => true,
41 26 100   26   110 builder => sub { $_[0]->class || $_[0]->compiling_class };
42              
43             has name =>
44             is => rw,
45             isa => NonEmptyStr,
46             required => true;
47              
48             has init_arg =>
49             is => rw,
50             isa => NonEmptyStr|Undef,
51             default => sub { shift->name },
52             lazy => true;
53              
54             has required =>
55             is => rw,
56             isa => Bool,
57             coerce => true,
58             default => false,
59             default_is_trusted => true;
60              
61             has weak_ref =>
62             is => rw,
63             isa => Bool,
64             default => false;
65              
66             has is =>
67             is => rw,
68             enum => [ ro, rw, rwp, 'lazy', bare, 'locked' ],
69             default => bare;
70              
71             has [ 'reader', 'writer', 'accessor', 'clearer', 'predicate', 'lvalue', 'local_writer' ] =>
72             is => rw,
73             isa => MethodNameTemplate|One|Undef,
74             builder => true,
75             lazy => true;
76              
77             has isa =>
78             is => bare,
79             isa => Str|Ref,
80             reader => '_%s'; # collision with UNIVERSAL::isa
81              
82             has does =>
83             is => bare,
84             isa => Str|Ref,
85             reader => '_%s'; # collision with Mite's does method
86              
87             has enum =>
88             is => rw,
89             isa => ArrayRef[NonEmptyStr],
90             predicate => true;
91              
92             has type =>
93             is => 'lazy',
94             isa => Object|Undef,
95             builder => true;
96              
97             has coerce =>
98             is => rw,
99             isa => Bool,
100             default => false;
101              
102             has locked =>
103             is => rw,
104             isa => Bool,
105             default => false;
106              
107             has default =>
108             is => rw,
109             isa => Undef | Str | CodeRef | ScalarRef | Dict[] | Tuple[],
110             documentation => 'We support more possibilities than Moose!',
111             predicate => true;
112              
113             has [ 'default_is_trusted', 'default_does_trigger', 'skip_argc_check' ] =>
114             is => rw,
115             isa => Bool,
116             coerce => true,
117             default => false,
118             default_is_trusted => true;
119              
120             has lazy =>
121             is => rw,
122             isa => Bool,
123             default => false;
124              
125             has coderef_default_variable =>
126             is => rw,
127             isa => NonEmptyStr,
128             lazy => true, # else $self->name might not be set
129             default => sub {
130             # This must be coordinated with Mite.pm
131             return sprintf '$%s::__%s_DEFAULT__', $_[0]->_class_for_default->name, $_[0]->name;
132             };
133              
134             has [ 'trigger', 'builder' ] =>
135             is => rw,
136             isa => MethodNameTemplate|One|CodeRef,
137             predicate => true;
138              
139             has clone =>
140             is => bare,
141             isa => MethodNameTemplate|One|CodeRef|Undef,
142             reader => 'cloner_method';
143              
144             has [ 'clone_on_read', 'clone_on_write' ] =>
145             is => 'lazy',
146             isa => Bool,
147             coerce => true,
148 230     230   1071 builder => sub { !! shift->cloner_method };
149              
150             has documentation =>
151             is => rw,
152             predicate => true;
153              
154             has handles =>
155             is => rw,
156             isa => HandlesHash | Enum[ 1, 2 ],
157             predicate => true,
158             coerce => true;
159              
160             has handles_via =>
161             is => rw,
162             isa => ArrayRef->of( Str )->plus_coercions( Str, q{ [$_] } ),
163             predicate => true,
164             coerce => true;
165              
166             has alias =>
167             is => rw,
168             isa => AliasList,
169             coerce => true,
170             default => sub { [] };
171              
172             has alias_is_for =>
173             is => 'lazy',
174             init_arg => undef;
175              
176 287     287   1238 sub _q { shift; join q[, ], map B::perlstring($_), @_ }
  287         2405  
177 501     501   1769 sub _q_name { B::perlstring( shift->name ) }
178 268     268   498 sub _q_init_arg { my $self = shift; B::perlstring( $self->_expand_name( $self->init_arg ) ) }
  268         752  
179              
180             for my $function ( qw/ carp croak confess / ) {
181 79     79   1220 no strict 'refs';
  79         295  
  79         787405  
182             *{"_function_for_$function"} = sub {
183 129     129   403 my $self = shift;
184 129 100       634 return $self->compiling_class->${\"_function_for_$function"}
  124         810  
185             if defined $self->compiling_class;
186 5         10 my $shim = eval { $self->class->shim_name };
  5         14  
187 5 50       23 return "$shim\::$function" if $shim;
188 5 50       52 $function eq 'carp' ? 'warn sprintf' : 'die sprintf';
189             };
190             }
191              
192             sub _function_for_lock {
193 2     2   3 my $self = shift;
194             my $ns = $self->compiling_class->imported_functions->{lock} ? ''
195 2 50 50     14 : ( eval { $self->compiling_class->shim_name } || eval { $self->class->shim_name } || die() );
196 2         8 return "$ns\::lock";
197             }
198              
199             sub _function_for_unlock {
200 1     1   3 my $self = shift;
201             my $ns = $self->compiling_class->imported_functions->{unlock} ? ''
202 1 50 50     3 : ( eval { $self->compiling_class->shim_name } || eval { $self->class->shim_name } || die() );
203 1         5 return "$ns\::unlock";
204             }
205              
206             my @method_name_generator = (
207             { # public
208             reader => sub { "get_$_" },
209             writer => sub { "set_$_" },
210             accessor => sub { $_ },
211             lvalue => sub { $_ },
212             clearer => sub { "clear_$_" },
213             predicate => sub { "has_$_" },
214             builder => sub { "_build_$_" },
215             trigger => sub { "_trigger_$_" },
216             local_writer => sub { "locally_set_$_" },
217             clone => sub { "_clone_$_" },
218             },
219             { # private
220             reader => sub { "_get_$_" },
221             writer => sub { "_set_$_" },
222             accessor => sub { $_ },
223             lvalue => sub { $_ },
224             clearer => sub { "_clear_$_" },
225             predicate => sub { "_has_$_" },
226             builder => sub { "_build_$_" },
227             trigger => sub { "_trigger_$_" },
228             local_writer => sub { "_locally_set_$_" },
229             clone => sub { "_clone_$_" },
230             },
231             );
232              
233             sub BUILD {
234 173     173 0 496 my $self = shift;
235              
236 173 50 66     1156 croak "Required attribute with no init_arg"
237             if $self->required && !defined $self->init_arg;
238              
239 173 100       1029 if ( $self->is eq 'lazy' ) {
    50          
240 4         38 $self->lazy( true );
241 4 100 66     59 $self->builder( true ) unless $self->has_builder || $self->has_default;
242 4         31 $self->is( ro );
243             }
244             elsif ( $self->is eq 'locked' ) {
245 0         0 $self->locked( true );
246 0         0 $self->is( ro );
247             }
248              
249 173 50 66     1348 if ( $self->has_builder and $self->has_default ) {
250 0         0 croak "Attribute cannot have both default and builder.";
251             }
252              
253 173         665 for my $method_type ( 'builder', 'trigger' ) {
254 346 100       2559 if ( CodeRef->check( $self->$method_type ) ) {
255 7         109 $self->$method_type( true );
256             }
257             }
258              
259 173         1471 for my $method_type ( 'reader', 'writer', 'accessor', 'clearer', 'predicate', 'builder', 'trigger', 'lvalue', 'local_writer' ) {
260 1557         6676 my $name = $self->$method_type;
261 1557 100 100     4626 if ( defined $name and $name eq true ) {
262 44         211 my $gen = $method_name_generator[$self->is_private]{$method_type};
263 44         139 local $_ = $self->name;
264 44         323 my $newname = $gen->( $_ );
265 44         169 $self->$method_type( $newname );
266             }
267             }
268              
269 173 100       579 if ( defined $self->lvalue ) {
270 9 100       42 croak( 'Attributes with lazy defaults cannot have an lvalue accessor' )
271             if $self->lazy;
272 7 100       24 croak( 'Attributes with triggers cannot have an lvalue accessor' )
273             if $self->trigger;
274 5 100       30 croak( 'Attributes with weak_ref cannot have an lvalue accessor' )
275             if $self->weak_ref;
276 3 100 66     33 croak( 'Attributes with type constraints or coercions cannot have an lvalue accessor' )
277             if $self->type || $self->coerce;
278 1 50       10 croak( 'Attributes with autoclone cannot have an lvalue accessor' )
279             if $self->cloner_method;
280             }
281             }
282              
283             sub _expand_name {
284 599     599   1339 my ( $self, $name ) = @_;
285              
286 599 100       1473 return undef unless defined $name;
287 585 100       3680 return $name unless $name =~ /\%/;
288              
289 127         481 my %tokens = (
290             's' => $self->name,
291             '%' => '%',
292             );
293              
294 127         930 $name =~ s/%(.)/$tokens{$1}/eg;
  127         601  
295 127         618 return $name;
296             }
297              
298             sub clone {
299 7     7 0 47 my ( $self, %args ) = ( shift, @_ );
300              
301 7 50       34 if ( exists $args{is} ) {
302 0         0 croak "Cannot use the `is` shortcut when extending an attribute";
303             }
304              
305 7         135 my %inherit = %$self;
306              
307             # type will need to be rebuilt
308 7 50 33     76 delete $inherit{type} if $args{isa} || $args{type};
309              
310             # these should not be cloned at all
311 7         20 delete $inherit{coderef_default_variable};
312 7         28 delete $inherit{_order};
313              
314             # Allow child class to switch from default to builder
315             # or vice versa.
316 7 100 66     67 if ( exists $args{builder} or exists $args{default} ) {
317 4         16 delete $inherit{builder};
318 4         10 delete $inherit{default};
319             }
320              
321 7         89 return ref($self)->new( %inherit, %args );
322             }
323              
324             sub is_private {
325 44     44 0 204 0+!! ( shift->name =~ /^_/ );
326             }
327              
328             sub _build_reader {
329 163     163   386 my $self = shift;
330 163 100 100     563 ( $self->is eq ro or $self->is eq rwp ) ? '%s' : undef;
331             }
332              
333             sub _build_writer {
334 162     162   358 my $self = shift;
335 162 100       485 ( $self->is eq rwp ) ? '_set_%s' : undef;
336             }
337              
338             sub _build_accessor {
339 162     162   344 my $self = shift;
340 162 100       480 ( $self->is eq rw ) ? '%s' : undef;
341             }
342              
343 163     163   443 sub _build_predicate { undef; }
344              
345 163     163   620 sub _build_clearer { undef; }
346              
347 157     157   377 sub _build_lvalue { undef; }
348              
349 165     165   416 sub _build_local_writer { undef; }
350              
351             sub _build_alias_is_for {
352 119     119   309 my $self = shift;
353 119 100       292 return undef unless @{ $self->alias };
  119         383  
354 2 100       7 my @seek_order = $self->is eq rw
355             ? qw( accessor reader lvalue writer )
356             : qw( reader accessor lvalue writer );
357 2         4 for my $sought ( @seek_order ) {
358 2 50       7 return $sought if $self->$sought;
359             }
360 0         0 return undef;
361             }
362              
363             sub _all_aliases {
364 258     258   492 my $self = shift;
365 258         848 my $aliases = $self->alias;
366 258 100       1400 return unless @$aliases;
367 6         22 map $self->_expand_name($_), @$aliases;
368             }
369              
370             sub associated_methods {
371 1     1 0 3 my $self = shift;
372              
373 1         4 my @methods = grep defined, (
374             $self->_all_aliases,
375             map(
376             $self->_expand_name($self->$_),
377             qw( reader writer accessor clearer predicate lvalue local_writer builder trigger cloner_method ),
378             ),
379             );
380              
381 1 50       7 if ( ref $self->handles ) {
    0          
382 1 50       6 if ( ! $self->handles_via ) {
383 1         3 push @methods, sprintf '_assert_blessed_%s', $self->name;
384             }
385 1         6 push @methods, map $self->_expand_name($_), sort keys %{ $self->handles };
  1         3  
386             }
387             elsif ( $self->handles ) {
388 0         0 my %delegations = $self->_compile_native_delegations;
389 0         0 push @methods, sort keys %delegations;
390             }
391              
392 1         7 return @methods;
393             }
394              
395             sub _build_type {
396 121     121   337 my $self = shift;
397              
398 121         866 my ( $fallback, $string );
399 121 100       1284 if ( my $isa = $self->_isa ) {
    50          
    100          
400 19         69 $string = $isa;
401 19         170 $fallback = [ 'make_class_type' ];
402             }
403             elsif ( my $does = $self->_does ) {
404 0         0 $string = $does;
405 0         0 $fallback = [ 'make_role_type' ];
406             }
407             elsif ( $self->has_enum ) {
408 2         15 require Types::Standard;
409 2         11 return Types::Standard::Enum()->of( @{ $self->enum } );
  2         31  
410             }
411             else {
412 100         355 return undef;
413             }
414              
415 19         68 my $type;
416 19 100       142 if ( ref $string ) {
417 2         9 $type = $string;
418              
419 2 50 66     81 if ( blessed $type and not $type->isa( 'Type::Tiny' ) ) {
    100          
420 0 0       0 if ( $type->can( 'to_TypeTiny' ) ) {
421 0         0 $type = $type->to_TypeTiny;
422             }
423             else {
424 0         0 require Types::TypeTiny;
425 0         0 $type = $type->Types::TypeTiny::to_TypeTiny;
426             }
427             }
428             elsif ( not blessed $type ) {
429 1         7 require Types::TypeTiny;
430 1         5 $type = Types::TypeTiny::to_TypeTiny( $type );
431             }
432             }
433             else {
434 17         137 require Type::Utils;
435 17         122 $type = Type::Utils::dwim_type(
436             $string,
437             fallback => $fallback,
438             for => $self->class->name,
439             );
440              
441 17 50       5158 $type or croak 'Type %s cannot be found', $string;
442             }
443              
444 19 50       574 $type->can_be_inlined
445             or croak 'Type %s cannot be inlined', $type->display_name;
446              
447 19 100       545 if ( $self->coerce ) {
448 6 50       29 $type->has_coercion
449             or carp 'Type %s has no coercions', $type->display_name;
450 6 50       1932 $type->coercion->can_be_inlined
451             or carp 'Coercion to type %s cannot be inlined', $type->display_name;
452             }
453              
454 19         627 return $type;
455             }
456              
457             sub possible_values {
458 2     2 0 5 my $self = shift;
459            
460 2         4 my $values;
461 2 50       18 if ( $self->has_enum ) {
462 2         20 $values = $self->enum;
463             }
464 2 50 33     16 if ( not $values and my $type = $self->type ) {
465 0         0 require Types::Standard;
466             my $enum = $type->find_parent( sub {
467 0     0   0 $_->isa( 'Type::Tiny::Enum' );
468 0         0 } );
469 0 0       0 if ( $enum ) {
470 0         0 $values = $enum->unique_values;
471             }
472             }
473              
474             my %return = map {
475 2         7 my $label = $_;
  6         12  
476 6         8 my $value = $_;
477 6         12 $label =~ s/([\W])/sprintf('_%x', ord($1))/ge;
  0         0  
478 6         17 $label => $value;
479             } @$values;
480              
481 2         13 return \%return;
482             }
483              
484             sub has_coderef_default {
485 89     89 0 188 my $self = shift;
486              
487             # We don't have a default
488 89 50       421 return 0 unless $self->has_default;
489              
490 89         415 return CodeRef->check( $self->default );
491             }
492              
493             sub has_inline_default {
494 40     40 0 490 my $self = shift;
495              
496             # We don't have a default
497 40 50       234 return 0 unless $self->has_default;
498              
499 40         306 return ScalarRef->check( $self->default );
500             }
501              
502             sub has_reference_default {
503 39     39 0 422 my $self = shift;
504              
505             # We don't have a default
506 39 50       215 return 0 unless $self->has_default;
507              
508 39   100     216 return HashRef->check( $self->default ) || ArrayRef->check( $self->default );
509             }
510              
511             sub has_simple_default {
512 91     91 0 28851 my $self = shift;
513              
514 91 50       328 return 0 unless $self->has_default;
515              
516 91         308 return !ref $self->default;
517             }
518              
519             sub _compile_check {
520 45     45   413 my ( $self, $varname ) = @_;
521              
522             my $type = $self->type
523 45 0       174 or return ( $self->imported_functions->{true} ? 'true' : '!!1' );
    50          
524              
525 45         372 my $code = undef;
526              
527 45 50 33     151 if ( $self->compiling_class
528             and $self->compiling_class->imported_functions->{blessed} ) {
529 0         0 my $ctype = $type->find_constraining_type;
530              
531 0 0       0 if ( $ctype == Object ) {
    0          
532 0         0 $code = "blessed( $varname )";
533             }
534             elsif ( $ctype->isa( 'Type::Tiny::Class' ) ) {
535 0         0 $code = sprintf 'blessed( %s ) && %s->isa( %s )',
536             $varname, $varname, $self->_q( $ctype->class );
537             }
538             }
539              
540 45   33     294 $code //= do {
541 45         100 local $Type::Tiny::AvoidCallbacks = 1;
542 45         161 $type->inline_check( $varname );
543             };
544              
545 45 50       3757 if ( my $autolax = $self->autolax ) {
546 0         0 $code = "( !$autolax or $code )";
547             }
548              
549 45         1827 return $code;
550             }
551              
552             sub _compile_coercion {
553 15     15   92 my ( $self, $expression ) = @_;
554 15 50 33     53 if ( $self->coerce and my $type = $self->type ) {
555 15         156 local $Type::Tiny::AvoidCallbacks = 1;
556 15         45 return sprintf 'do { my $to_coerce = %s; %s }',
557             $expression, $type->coercion->inline_coercion( '$to_coerce' );
558             }
559 0         0 return $expression;
560             }
561              
562             sub _compile_checked_default {
563 20     20   113 my ( $self, $selfvar ) = @_;
564              
565 20         78 my $default = $self->_compile_default( $selfvar );
566 20 100       114 return $default if $self->default_is_trusted;
567 19 100       107 my $type = $self->type or return $default;
568              
569 7 100       62 if ( $self->coerce ) {
570 3         11 $default = $self->_compile_coercion( $default );
571             }
572              
573 7         681 return sprintf 'do { my $default_value = %s; %s or %s( "Type check failed in default: %%s should be %%s", %s, %s ); $default_value }',
574             $default, $self->_compile_check('$default_value'), $self->_function_for_croak, $self->_q($self->name), $self->_q($type->display_name);
575             }
576              
577             sub _compile_default {
578 81     81   278 my ( $self, $selfvar ) = @_;
579              
580 81 100 66     661 if ( $self->has_builder ) {
    100 66        
    100          
    100          
    50          
    50          
581 13         57 return sprintf '%s->%s', $selfvar, $self->_expand_name( $self->builder );
582             }
583             elsif ( $self->has_coderef_default ) {
584 28         384 my $var = $self->coderef_default_variable;
585 28         200 return sprintf '%s->( %s )', $var, $selfvar;
586             }
587             elsif ( $self->has_inline_default ) {
588 1         10 return ${ $self->default };
  1         4  
589             }
590             elsif ( $self->has_reference_default ) {
591 4 100       53 return HashRef->check( $self->default ) ? '{}' : '[]';
592             }
593             elsif ( $self->has_simple_default and $self->type and $self->type == Bool ) {
594 0 0       0 my $truthy = $self->compiling_class->imported_functions->{true} ? 'true' : '!!1';
595 0 0       0 my $falsey = $self->compiling_class->imported_functions->{false} ? 'false' : '!!0';
596 0 0       0 return $self->default ? $truthy : $falsey;
597             }
598             elsif ( $self->has_simple_default ) {
599 35 100       151 return defined( $self->default ) ? $self->_q( $self->default ) : 'undef';
600             }
601              
602             # should never get here
603 0         0 return 'undef';
604             }
605              
606             sub _compile_trigger {
607 11     11   41 my ( $self, $selfvar, @args ) = @_;
608 11         34 my $method_name = $self->_expand_name( $self->trigger );
609              
610 11         78 return sprintf '%s->%s( %s )',
611             $selfvar, $method_name, join( q{, }, @args );
612             }
613              
614             sub _compile_clone {
615 12     12   29 my ( $self, $selfvar, $valuevar ) = @_;
616              
617 12 100       76 if ( 'CODE' eq ref $self->cloner_method ) {
618 2         14 return sprintf '%s->_clone_%s( %s, %s )',
619             $selfvar, $self->name, $self->_q( $self->name ), $valuevar;
620             }
621              
622 10 100       34 if ( MethodNameTemplate->check( $self->cloner_method ) ) {
623 2         62 return sprintf '%s->%s( %s, %s )',
624             $selfvar, $self->_expand_name( $self->cloner_method ), $self->_q( $self->name ), $valuevar;
625             }
626              
627 8         269 return "Storable::dclone( $valuevar )";
628             }
629              
630             sub _sanitize_identifier {
631 2 50   2   15 ( my $str = pop ) =~ s/([_\W])/$1 eq '_' ? '__' : sprintf('_%x', ord($1))/ge;
  2         12  
632 2         7 $str;
633             }
634              
635             sub compile_init {
636 129     129 0 432 my ( $self, $selfvar, $argvar ) = @_;
637              
638 129         322 my @code;
639              
640 129         572 my $init_arg = $self->_expand_name( $self->init_arg );
641              
642 129 100 66     640 if ( defined $init_arg ) {
    50 66        
643              
644 126 100       600 if ( my @alias = $self->_all_aliases ) {
645 2         8 my $new_argvar = "\$args_for_" . $self->_sanitize_identifier( $self->name );
646 2         19 push @code, sprintf( 'my %s = {};', $new_argvar );
647 2         5 push @code, sprintf 'for ( %s, %s ) { next unless exists %s->{$_}; %s->{%s} = %s->{$_}; last; }',
648             $self->_q_init_arg, $self->_q( @alias ), $argvar, $new_argvar, $self->_q_init_arg, $argvar;
649 2         6 $argvar = $new_argvar;
650             }
651              
652 126         322 my $code;
653 126         680 my $valuevar = sprintf '%s->{%s}', $argvar, $self->_q_init_arg;
654 126         500 my $postamble = '';
655 126         290 my $needs_check = 1;
656              
657 126 100       596 if ( $self->clone_on_write ) {
658 5         19 push @code, sprintf '%s = %s if exists( %s );',
659             $valuevar, $self->_compile_clone( $selfvar, $valuevar ), $valuevar;
660             }
661              
662 126 100 100     1691 if ( $self->has_default || $self->has_builder and not $self->lazy ) {
    100 100        
      66        
663 61 100 66     281 if ( $self->default_is_trusted and my $type = $self->type ) {
    100          
664 1         8 my $coerce_and_check;
665 1         3 local $Type::Tiny::AvoidCallbacks = 1;
666 1 50       4 if ( $type->has_coercion ) {
667 1         26 $coerce_and_check = sprintf 'do { my $coerced_value = %s; ( %s ) ? $coerced_value : %s( "Type check failed in constructor: %%s should be %%s", %s, %s ) }',
668             $self->_compile_coercion( $valuevar ), $self->_compile_check( '$coerced_value' ), $self->_function_for_croak, $self->_q_init_arg, $self->_q( $type->display_name );
669             }
670             else {
671 0         0 $coerce_and_check = sprintf '( ( %s ) ? %s : %s( "Type check failed in constructor: %%s should be %%s", %s, %s ) )',
672             $self->_compile_check( $valuevar ), $valuevar, $self->_function_for_croak, $self->_q_init_arg, $self->_q( $type->display_name );
673             }
674 1         14 $code .= sprintf 'do { my $value = exists( %s ) ? %s : %s; ',
675             $valuevar, $coerce_and_check, $self->_compile_default( $selfvar );
676 1         3 $valuevar = '$value';
677 1         3 $postamble = "}; $postamble";
678 1         3 $needs_check = 0;
679             }
680             elsif ( $self->type ) {
681 6         113 $code .= sprintf 'do { my $value = exists( %s ) ? %s : %s; ',
682             $valuevar, $valuevar, $self->_compile_default( $selfvar );
683 6         46 $valuevar = '$value';
684 6         22 $postamble = "}; $postamble";
685             }
686             else {
687 54         339 $valuevar = sprintf '( exists( %s ) ? %s : %s )',
688             $valuevar, $valuevar, $self->_compile_default( $selfvar );
689             }
690              
691 61 100 66     402 my $trigger_condition_code =
692             ( $self->default_does_trigger and ! $self->lazy and $self->has_default || $self->has_builder )
693             ? '; '
694             : sprintf( ' if exists %s->{%s}; ', $argvar, $self->_q_init_arg );
695 61 100       299 my $trigger_code = $self->trigger
696             ? $self->_compile_trigger(
697             $selfvar,
698             sprintf( '%s->{%s}', $selfvar, $self->_q_name ),
699             ) . $trigger_condition_code
700             : '';
701 61         215 $postamble = $trigger_code . $postamble;
702             }
703             elsif ( $self->required and not $self->lazy ) {
704 6         33 push @code, sprintf '%s "Missing key in constructor: %s" unless exists %s; ',
705             $self->_function_for_croak, $init_arg, $valuevar;
706             }
707             else {
708 59 100       403 my $trigger_code = $self->trigger
709             ? $self->_compile_trigger(
710             $selfvar,
711             sprintf( '%s->{%s}', $selfvar, $self->_q_name ),
712             ) . '; '
713             : '';
714              
715 59         247 $code .= sprintf 'if ( exists %s->{%s} ) { ',
716             $argvar, $self->_q_init_arg;
717 59         301 $postamble = "$trigger_code} $postamble";
718             }
719              
720 126 100 100     992 if ( $needs_check and my $type = $self->type ) {
721 18 100       265 if ( $self->coerce ) {
722 5         45 $code .= sprintf 'do { my $coerced_value = %s; ', $self->_compile_coercion( $valuevar );
723 5         1753 $valuevar = '$coerced_value';
724 5         18 $postamble = "}; $postamble";
725             }
726              
727 18         152 $code .= sprintf '%s or %s "Type check failed in constructor: %%s should be %%s", %s, %s; ',
728             $self->_compile_check( $valuevar ),
729             $self->_function_for_croak,
730             $self->_q_init_arg,
731             $self->_q( $type->display_name );
732              
733 18         123 $code .= sprintf '%s->{%s} = %s; ',
734             $selfvar, $self->_q_name, $valuevar;
735             }
736             else {
737 108         453 $code .= sprintf '%s->{%s} = %s; ',
738             $selfvar, $self->_q_name, $valuevar;
739             }
740            
741 126         368 $code .= $postamble;
742 126         424 push @code, $code;
743             }
744             elsif ( $self->has_default || $self->has_builder and not $self->lazy ) {
745 0         0 push @code, sprintf '%s->{%s} = %s; ',
746             $selfvar, $self->_q_name, $self->_compile_checked_default( $selfvar );
747             }
748              
749 129 100       554 if ( $self->weak_ref ) {
750 1         3 push @code, sprintf 'require Scalar::Util && Scalar::Util::weaken(%s->{%s}) if ref %s->{%s};',
751             $selfvar, $self->_q_name, $selfvar, $self->_q_name;
752             }
753              
754 129 100       555 if ( $self->locked ) {
755 1         5 push @code, sprintf '%s(%s->{%s}) if ref %s->{%s};',
756             $self->_function_for_lock, $selfvar, $self->_q_name, $selfvar, $self->_q_name;
757             }
758              
759 129         434 for ( @code ) {
760 143 100       1176 $_ = "$_;" unless /;\s*$/;
761             }
762              
763 129         842 return @code;
764             }
765              
766             sub autolax {
767 111     111 0 287 my $self = shift;
768              
769 111 100       386 if ( my $class = $self->compiling_class ) {
770 106         674 return $class->autolax;
771             }
772 5 50       17 return if not $self->class;
773 0 0       0 return if not eval { $self->class->project->config->data->{autolax} };
  0         0  
774 0         0 return sprintf '%s::STRICT', $self->class->project->config->data->{shim};
775             }
776              
777             my $make_usage = sub {
778             my ( $self, $code, $check, $usage_info, %arg ) = @_;
779             $arg{skip_argc_check} and return $code;
780             $self->skip_argc_check and return $code;
781              
782             my $label = ucfirst $arg{label};
783             $label .= sprintf ' "%s"', $arg{name}
784             if defined $arg{name};
785              
786             if ( my $autolax = $self->autolax ) {
787             $check = "!$autolax or $check"
788             }
789              
790             return sprintf q{%s or %s( '%s usage: $self->%s(%s)' ); %s},
791             $check, $self->_function_for_croak, $label, $arg{name} || '$METHOD', $usage_info, $code;
792             };
793              
794             my %code_template;
795             %code_template = (
796             reader => sub {
797             my $self = shift;
798             my %arg = @_;
799             my $code = sprintf '$_[0]{%s}', $self->_q_name;
800             if ( $self->lazy ) {
801             my $checked_default = $self->_compile_checked_default( '$_[0]' );
802             my $maybe_lock = '';
803             if ( $self->default_does_trigger ) {
804             $checked_default = sprintf 'do { my $default = %s; %s; $default }',
805             $checked_default, $self->_compile_trigger( '$_[0]', '$default' );
806             }
807             if ( $self->locked ) {
808             $maybe_lock = $self->_function_for_lock;
809             }
810             $code = sprintf '( exists($_[0]{%s}) ? $_[0]{%s} : %s( $_[0]{%s} = %s ) )',
811             $self->_q_name, $self->_q_name, $maybe_lock, $self->_q_name, $checked_default;
812             }
813             if ( $self->clone_on_read ) {
814             $code = $self->_compile_clone( '$_[0]', $code );
815             }
816             return $make_usage->( $self, $code, '@_ == 1', '', label => 'reader', %arg );
817             },
818             asserter => sub {
819             my $self = shift;
820             my %arg = @_;
821             my $reader = $code_template{reader}->( $self, skip_argc_check => true );
822             my $blessed = 'require Scalar::Util && Scalar::Util::blessed';
823             if ( $self->compiling_class and $self->compiling_class->imported_functions->{blessed} ) {
824             $blessed = 'blessed';
825             }
826             return sprintf 'my $object = do { %s }; %s($object) or %s( "%s is not a blessed object" ); $object',
827             $reader, $blessed, $self->_function_for_croak, $self->name;
828             },
829             writer => sub {
830             my $self = shift;
831             my %arg = @_;
832             my $code = '';
833             if ( $self->trigger ) {
834             $code .= sprintf 'my @oldvalue; @oldvalue = $_[0]{%s} if exists $_[0]{%s}; ',
835             $self->_q_name, $self->_q_name;
836             }
837             my $valuevar = '$_[1]';
838             if ( my $type = $self->type ) {
839             if ( $self->coerce ) {
840             $code .= sprintf 'my $value = %s; ', $self->_compile_coercion($valuevar);
841             $valuevar = '$value';
842             }
843             $code .= sprintf '%s or %s( "Type check failed in %%s: value should be %%s", %s, %s ); ',
844             $self->_compile_check($valuevar), $self->_function_for_croak, $self->_q( $arg{label} // 'writer' ), $self->_q( $type->display_name );
845             }
846             if ( $self->clone_on_write ) {
847             $code .= sprintf 'my $cloned = %s; ',
848             $self->_compile_clone( '$_[0]', $valuevar );
849             $valuevar = '$cloned';
850             }
851             $code .= sprintf '$_[0]{%s} = %s; ',
852             $self->_q_name,
853             $valuevar;
854             if ( $self->trigger ) {
855             $code .= ' ' . $self->_compile_trigger(
856             '$_[0]',
857             sprintf( '$_[0]{%s}', $self->_q_name ),
858             '@oldvalue',
859             ) . '; ';
860             }
861             if ( $self->weak_ref ) {
862             $code .= sprintf 'require Scalar::Util && Scalar::Util::weaken($_[0]{%s}) if ref $_[0]{%s}; ',
863             $self->_q_name, $self->_q_name;
864             }
865             if ( $self->locked ) {
866             $code .= sprintf '%s($_[0]{%s}) if ref $_[0]{%s}; ',
867             $self->_function_for_lock, $self->_q_name, $self->_q_name;
868             }
869             $code .= '$_[0];';
870             return $make_usage->( $self, $code, '@_ == 2', ' $newvalue ', label => 'writer', %arg );
871             },
872             accessor => sub {
873             my $self = shift;
874             my %arg = @_;
875             my @parts = (
876             $code_template{writer}->( $self, skip_argc_check => true, label => 'accessor' ),
877             $code_template{reader}->( $self, skip_argc_check => true ),
878             );
879             for my $i ( 0 .. 1 ) {
880             $parts[$i] = $parts[$i] =~ /\;/
881             ? "do { $parts[$i] }"
882             : "( $parts[$i] )"
883             }
884             my $code = sprintf '@_ > 1 ? %s : %s', @parts;
885             },
886             clearer => sub {
887             my $self = shift;
888             my %arg = @_;
889             my $code = sprintf 'delete $_[0]{%s}; $_[0];', $self->_q_name;
890             return $make_usage->( $self, $code, '@_ == 1', '', label => 'clearer', %arg );
891             },
892             predicate => sub {
893             my $self = shift;
894             my %arg = @_;
895             my $code = sprintf 'exists $_[0]{%s}', $self->_q_name;
896             return $make_usage->( $self, $code, '@_ == 1', '', label => 'predicate', %arg );
897             },
898             lvalue => sub {
899             my $self = shift;
900             my %arg = @_;
901             my $code = sprintf '$_[0]{%s}', $self->_q_name;
902             return $make_usage->( $self, $code, '@_ == 1', '', label => 'lvalue', %arg );
903             },
904             local_writer => sub {
905             my $self = shift;
906             my %arg = @_;
907              
908             my $CROAK = $self->_function_for_croak;
909             my $GET = $self->reader ? $self->_q( $self->_expand_name( $self->reader ) )
910             : $self->accessor ? $self->_q( $self->_expand_name( $self->accessor ) )
911             : sprintf( 'sub { %s }', $code_template{reader}->( $self, skip_argc_check => true ) );
912             my $SET = $self->writer ? $self->_q( $self->_expand_name( $self->writer ) )
913             : $self->accessor ? $self->_q( $self->_expand_name( $self->accessor ) )
914             : sprintf( 'sub { %s }', $code_template{writer}->( $self, skip_argc_check => true, label => 'local writer' ) );
915             my $HAS = $self->predicate ? $self->_q( $self->_expand_name( $self->predicate ) )
916             : sprintf( 'sub { %s }', $code_template{predicate}->( $self, skip_argc_check => true ) );
917             my $CLEAR = $self->clearer ? $self->_q( $self->_expand_name( $self->clearer ) )
918             : sprintf( 'sub { %s }', $code_template{clearer}->( $self, skip_argc_check => true ) );
919             my $GUARD_NS = $self->compiling_class->imported_functions->{guard} ? ''
920             : ( eval { $self->compiling_class->shim_name } || eval { $self->class->shim_name } || die() );
921             $GUARD_NS .= '::' if $GUARD_NS;
922              
923             return sprintf <<'CODE', $CROAK, $GET, $SET, $HAS, $CLEAR, $GUARD_NS;
924              
925             defined wantarray or %s( "This method cannot be called in void context" );
926             my $get = %s;
927             my $set = %s;
928             my $has = %s;
929             my $clear = %s;
930             my $old = undef;
931             my ( $self, $new ) = @_;
932             my $restorer = $self->$has
933             ? do { $old = $self->$get; sub { $self->$set( $old ) } }
934             : sub { $self->$clear };
935             @_ == 2 ? $self->$set( $new ) : $self->$clear;
936             &%sguard( $restorer, $old );
937             CODE
938             },
939             );
940              
941             my %code_attr = (
942             lvalue => ' :lvalue',
943             );
944              
945             sub _compile_native_delegations {
946 2     2   5 my $self = shift;
947 2         2 my $prefix;
948 2 100       8 if ( $self->handles eq 1 ) {
    50          
949 1         2 $prefix = "is_";
950             }
951             elsif ( $self->handles eq 2 ) {
952 1         12 $prefix = $self->name . "_is_";
953             }
954              
955 2 50       15 if ( defined $prefix ) {
956 2         6 my $needs_reader = 0;
957 2         2 my $reader;
958 2 50 33     11 if ( $self->lazy or $self->clone_on_read ) {
959             $reader = $self->_expand_name( $self->reader )
960             // $self->_expand_name( $self->accessor )
961             // $self->_expand_name( $self->lvalue )
962 0   0     0 // do { $needs_reader++; '_get_value_for_' . $self->name };
  0   0     0  
  0   0     0  
963             }
964             else {
965 2         7 $reader = sprintf '{%s}', $self->_q_name;
966             }
967            
968 2         8 my %values = %{ $self->possible_values };
  2         12  
969             my %native_delegations = map {
970 2         15 my $method_name = "$prefix$_";
  6         23  
971 6         10 my $value = $values{$_};
972 6         15 $method_name => sprintf( '$_[0]->%s eq %s', $reader, $self->_q( $value ) );
973             } keys %values;
974 2 50       11 if ( $needs_reader ) {
975 0         0 $native_delegations{$reader} = $code_template{reader}->( $self, name => $reader, skip_argc_check => true );
976             }
977 2         12 return \%native_delegations;
978             }
979              
980 0         0 return {};
981             }
982              
983             sub _shv_codegen {
984 3     3   7 my $self = shift;
985              
986 3   100     13 my $reader_method = $self->_expand_name(
      66        
987             $self->reader // $self->accessor // $self->lvalue
988             );
989 3   66     12 my $writer_method = $self->_expand_name(
990             $self->writer // $self->accessor
991             );
992             my $prelude = $self->locked
993             ? do {
994 1         3 my $name = $self->_q_name;
995 1         3 my $key = $self->_function_for_unlock;
996             sub {
997 1     1   23 sprintf 'my $mite_guard = %s(%s->{%s});',
998             $key, shift->generate_self, $name;
999 1         5 };
1000             }
1001 3 100   5   16 : sub { '' };
  5         97  
1002              
1003 3         1683 require Mite::Attribute::SHV::CodeGen;
1004              
1005             my $codegen = 'Mite::Attribute::SHV::CodeGen'->new(
1006             toolkit => '__DUMMY__',
1007             sandboxing_package => undef,
1008             target => ( $self->compiling_class || $self->class )->name,
1009             attribute => $self->name,
1010             env => {},
1011             isa => $self->type,
1012             coerce => $self->coerce,
1013             get_is_lvalue => ! defined( $reader_method ),
1014             set_checks_isa => defined( $writer_method ),
1015             set_strictly => $self->clone_on_read || $self->clone_on_write || $self->trigger,
1016             generator_for_get => sub {
1017 10     10   746 my ( $gen ) = @_;
1018 10 100       31 if ( defined $reader_method ) {
1019 9         28 return sprintf '%s->%s', $gen->generate_self, $reader_method;
1020             }
1021             else {
1022 1         7 return sprintf '%s->{%s}', $gen->generate_self, $self->_q_name;
1023             }
1024             },
1025             generator_for_set => sub {
1026 0     0   0 my ( $gen, $newvalue ) = @_;
1027 0 0       0 if ( defined $writer_method ) {
1028 0         0 return sprintf '%s->%s( %s )', $gen->generate_self, $writer_method, $newvalue;
1029             }
1030             else {
1031 0         0 return sprintf '( %s->{%s} = %s )', $gen->generate_self, $self->_q_name, $newvalue;
1032             }
1033             },
1034             generator_for_slot => sub {
1035 0     0   0 my ( $gen ) = @_;
1036 0         0 return sprintf '%s->{%s}', $gen->generate_self, $self->_q_name;
1037             },
1038             generator_for_default => sub {
1039 0     0   0 my ( $gen ) = @_;
1040 0         0 return $self->_compile_default( $gen->generate_self );
1041             },
1042             generator_for_type_assertion => sub {
1043 4     4   5904 local $Type::Tiny::AvoidCallbacks = 1;
1044 4         14 my ( $gen, $env, $type, $varname ) = @_;
1045 4 100 66     26 if ( $gen->coerce and $type->{uniq} == Bool->{uniq} ) {
1046 3         34 return sprintf '%s = !!%s;', $varname, $varname;
1047             }
1048 1 50 33     16 if ( $gen->coerce and $type->has_coercion ) {
1049 0         0 return sprintf 'do { my $coerced = %s; %s or %s("Type check failed after coercion in delegated method: expected %%s, got value %%s", %s, $coerced); $coerced };',
1050             $type->coercion->inline_coercion( $varname ), $type->inline_check( '$coerced' ), $self->_function_for_croak, $self->_q( $type->display_name );
1051             }
1052 1         7 return sprintf 'do { %s or %s("Type check failed in delegated method: expected %%s, got value %%s", %s, %s); %s };',
1053             $type->inline_check( $varname ), $self->_function_for_croak, $self->_q( $type->display_name ), $varname, $varname;
1054             },
1055 3   33     36 generator_for_prelude => $prelude,
      33        
1056             );
1057 3         889 $codegen->{mite_attribute} = $self;
1058 3         12 return $codegen;
1059             }
1060              
1061             sub _compile_delegations_via {
1062 3     3   7 my $self = shift;
1063              
1064 3         9 my $code = '';
1065 3         24 my $via = $self->handles_via;
1066 3 50       9 my %handles = %{ $self->handles } or return $code;
  3         15  
1067 3         16 my $gen = $self->_shv_codegen;
1068              
1069 3         1591 require Sub::HandlesVia::Handler;
1070 3         74281 local $Type::Tiny::AvoidCallbacks = 1;
1071              
1072 3         30 for my $method_name ( sort keys %handles ) {
1073             my $handler = 'Sub::HandlesVia::Handler'->lookup(
1074 6         84 $handles{$method_name},
1075             $via,
1076             );
1077 6         41856 $method_name = $self->_expand_name( $method_name );
1078 6         41 my $result = $gen->_generate_ec_args_for_handler( $method_name => $handler );
1079 6 100       2837 if ( keys %{ $result->{environment} } ) {
  6         33  
1080 1         774 require Data::Dumper;
1081 1         7056 my %env = %{ $result->{environment} };
  1         6  
1082 1         7 my $dd = Data::Dumper->new( [ \%env ], [ 'ENVIRONMENT' ] );
1083 1         37 my $env_dump = 'my ' . $dd->Purity( true )->Deparse( true )->Dump;
1084             $code .= sprintf "do {\n\t%s;%s\t*%s = %s;\n};\n",
1085             $env_dump,
1086 1         11 join( '', map { sprintf "\tmy %s = %s{\$ENVIRONMENT->{'%s'}};\n", $_, substr( $_, 0, 1 ), $_ } sort keys %env),
1087             $method_name,
1088 1         63 join( "\n", @{ $result->{source} } );
  1         23  
1089             }
1090             else {
1091             $code .= sprintf "*%s = %s;\n",
1092 5         13 $method_name, join( "\n", @{ $result->{source} } );
  5         78  
1093             }
1094             }
1095              
1096 3         104 return $code;
1097             }
1098              
1099             sub _compile_delegations {
1100 119     119   629 my ( $self, $asserter ) = @_;
1101              
1102 119 100       1030 $self->has_handles or return '';
1103              
1104 9         57 my $code = sprintf "# Delegated methods for %s\n", $self->name;
1105 9         51 $code .= '# ' . $self->definition_context_to_pretty_string. "\n";
1106              
1107 9 100       70 if ( $self->has_handles_via ) {
    100          
1108 3         17 return $code . $self->_compile_delegations_via;
1109             }
1110             elsif ( ref $self->handles ) {
1111 4         11 my %delegated = %{ $self->handles };
  4         19  
1112 4         38 for my $key ( sort keys %delegated ) {
1113             $code .= sprintf 'sub %s { shift->%s->%s( @_ ) }' . "\n",
1114 6         17 $self->_expand_name( $key ), $asserter, $delegated{$key};
1115             }
1116             }
1117             else {
1118 2         4 my %native_delegations = %{ $self->_compile_native_delegations };
  2         9  
1119 2         13 for my $method_name ( sort keys %native_delegations ) {
1120             $code .= sprintf "sub %s { %s }\n",
1121 6         25 $method_name, $native_delegations{$method_name};
1122             }
1123             }
1124 6         20 $code .= "\n";
1125              
1126 6         23 return $code;
1127             }
1128              
1129             sub compile {
1130 119     119 0 304 my $self = shift;
1131 119         568 my %args = @_;
1132              
1133             my $xs_condition = $args{xs_condition}
1134 119   100     555 || '!$ENV{PERL_ONLY} && eval { require Class::XSAccessor; Class::XSAccessor->VERSION("1.19") }';
1135 119         521 my $slot_name = $self->name;
1136              
1137 119         1006 my %xs_option_name = (
1138             reader => 'getters',
1139             writer => 'setters',
1140             accessor => 'accessors',
1141             predicate => 'exists_predicates',
1142             lvalue => 'lvalue_accessors',
1143             );
1144              
1145 119         496 my %want_xs;
1146             my %want_pp;
1147 119         0 my %method_name;
1148              
1149 119         971 for my $method_type ( keys %code_template ) {
1150 952 100       4063 my $method_name = $self->can($method_type) ? $self->$method_type : undef;
1151 952 100       2248 next unless defined $method_name;
1152              
1153 131         515 $method_name{$method_type} = $self->_expand_name( $method_name );
1154 131 100       591 if ( $xs_option_name{$method_type} ) {
1155 126         339 $want_xs{$method_type} = 1;
1156             }
1157 131         337 $want_pp{$method_type} = 1;
1158             }
1159              
1160 119 100 100     1161 if ( $self->has_handles and !$self->has_handles_via and ref $self->handles ) {
      100        
1161 4         14 $method_name{asserter} = sprintf '_assert_blessed_%s', $self->name;
1162 4         23 $want_pp{asserter} = 1;
1163             }
1164              
1165             # Class::XSAccessor can't do type checks, triggers, weaken, or cloning
1166 119 100 100     528 if ( $self->type or $self->weak_ref or $self->locked or $self->trigger or $self->clone_on_write ) {
      66        
      100        
      100        
1167 30         287 delete $want_xs{writer};
1168 30         84 delete $want_xs{accessor};
1169             }
1170              
1171             # Class::XSAccessor can't do lazy builders checks or cloning
1172 119 100 100     587 if ( $self->lazy or $self->clone_on_read ) {
1173 21         79 delete $want_xs{reader};
1174 21         56 delete $want_xs{accessor};
1175             }
1176              
1177 119         385 my $code = '';
1178 119 100 100     760 if ( keys %want_xs or keys %want_pp ) {
1179 112         492 $code .= "# Accessors for $slot_name\n";
1180 112         467 $code .= '# ' . $self->definition_context_to_pretty_string. "\n";
1181             }
1182              
1183 119 100       2627 if ( keys %want_xs ) {
1184 78         311 $code .= "if ( $xs_condition ) {\n";
1185 78         180 $code .= " Class::XSAccessor->import(\n";
1186 78         2241 $code .= " chained => 1,\n";
1187 78         283 for my $method_type ( sort keys %want_xs ) {
1188             $code .= sprintf " %s => { %s => %s },\n",
1189 82         339 $self->_q( $xs_option_name{$method_type} ), $self->_q( $method_name{$method_type} ), $self->_q_name;
1190             }
1191 78         230 $code .= " );\n";
1192 78         204 $code .= "}\n";
1193 78         179 $code .= "else {\n";
1194 78         251 for my $method_type ( sort keys %want_xs ) {
1195             $code .= sprintf ' *%s = sub%s { %s };' . "\n",
1196 82   100     936 $method_name{$method_type}, $code_attr{$method_type} || '', $code_template{$method_type}->( $self, name => $method_name{$method_type} );
1197 82         381 delete $want_pp{$method_type};
1198             }
1199 78         203 $code .= "}\n";
1200             }
1201              
1202 119         509 for my $method_type ( sort keys %want_pp ) {
1203             $code .= sprintf 'sub %s%s { %s }' . "\n",
1204 53   50     729 $method_name{$method_type}, $code_attr{$method_type} || '', $code_template{$method_type}->( $self, name => $method_name{$method_type} );
1205             }
1206              
1207 119         340 $code .= "\n";
1208              
1209 119 100 66     521 if ( $self->alias and my $alias_is_for = $self->alias_is_for ) {
1210 2         8 $code .= sprintf "# Aliases for %s\n", $self->name;
1211 2         5 $code .= '# ' . $self->definition_context_to_pretty_string. "\n";
1212 2         9 my $alias_target = $self->_expand_name( $self->$alias_is_for );
1213 2         7 for my $alias ( $self->_all_aliases ) {
1214 3         21 $code .= sprintf 'sub %s { shift->%s( @_ ) }' . "\n",
1215             $alias, $alias_target;
1216             }
1217 2         5 $code .= "\n";
1218             }
1219              
1220 119         795 $code .= $self->_compile_delegations( $method_name{asserter} );
1221              
1222 119         2904 return $code;
1223             }
1224              
1225             sub definition_context_to_string {
1226 0     0 0 0 my $self = shift;
1227 0         0 my %context = ( %{ $self->definition_context }, @_ );
  0         0  
1228              
1229             return sprintf '{ %s }',
1230             join q{, },
1231 0         0 map sprintf( '%s => %s', $_, B::perlstring( $context{$_} ) ),
1232             sort keys %context;
1233             }
1234              
1235             sub definition_context_to_pretty_string {
1236 249     249 0 566 my $self = shift;
1237 249         451 my %context = ( %{ $self->definition_context }, @_ );
  249         892  
1238              
1239             ( $context{context} and $context{file} and $context{line} )
1240 249 50 66     2380 or return '(unknown definition context)';
      33        
1241              
1242 224         1816 return sprintf( '%s, file %s, line %d', $context{context}, $context{file}, $context{line} );
1243             }
1244              
1245             sub _compile_mop {
1246 0     0     my $self = shift;
1247              
1248 0           my $opts_string = '';
1249 0           my $accessors_code = '';
1250 0           my $opts_indent = "\n ";
1251              
1252 0           $opts_string .= $opts_indent . '__hack_no_process_options => true,';
1253 0 0         if ( $self->compiling_class->isa('Mite::Class') ) {
1254 0           $opts_string .= $opts_indent . 'associated_class => $PACKAGE,';
1255             }
1256             else {
1257 0           $opts_string .= $opts_indent . 'associated_role => $PACKAGE,';
1258             }
1259              
1260 0           $opts_string .= $opts_indent . 'definition_context => ' . $self->definition_context_to_string . ',';
1261              
1262             {
1263 0           my %translate = ( ro => 'ro', rw => 'rw', rwp => 'ro', bare => 'bare', lazy => 'ro' );
  0            
1264 0   0       $opts_string .= $opts_indent . sprintf( 'is => "%s",', $translate{$self->is} || 'bare' );
1265             }
1266              
1267 0 0         $opts_string .= $opts_indent . sprintf( 'weak_ref => %s,', $self->weak_ref ? 'true' : 'false' );
1268              
1269             {
1270 0           my $init_arg = $self->init_arg;
  0            
1271 0 0         if ( defined $init_arg ) {
1272 0           $opts_string .= $opts_indent . sprintf( 'init_arg => %s,', $self->_q_init_arg );
1273 0 0         $opts_string .= $opts_indent . sprintf( 'required => %s,', $self->required ? 'true' : 'false' );
1274             }
1275             else {
1276 0           $opts_string .= $opts_indent . 'init_arg => undef,';
1277             }
1278             }
1279              
1280 0 0         if ( my $type = $self->type ) {
1281             # Easy case...
1282 0 0 0       if ( $type->name and $type->library ) {
    0 0        
    0 0        
      0        
      0        
      0        
      0        
1283 0           $opts_string .= $opts_indent . sprintf( 'type_constraint => do { require %s; %s::%s() },', $type->library, $type->library, $type->name );
1284             }
1285 0 0   0     elsif ( $type->isa( 'Type::Tiny::Union' ) and List::Util::all { $_->name and $_->library } @$type ) {
1286 0           my $requires = join q{; }, List::Util::uniq( map sprintf( 'require %s', $_->library ), @$type );
1287 0           my $union = join q{ | }, List::Util::uniq( map sprintf( '%s::%s()', $_->library, $_->name ), @$type );
1288 0           $opts_string .= $opts_indent . sprintf( 'type_constraint => do { %s; %s },', $requires, $union );
1289             }
1290             elsif ( $type->is_parameterized
1291 0           and 1 == @{ $type->parameters }
1292             and $type->parent->name
1293             and $type->parent->library
1294             and $type->type_parameter->name
1295             and $type->type_parameter->library ) {
1296 0           my $requires = join q{; }, List::Util::uniq( map sprintf( 'require %s', $_->library ), $type->parent, $type->type_parameter );
1297 0           my $ptype = sprintf( '%s::%s()->parameterize( %s::%s() )', $type->parent->library, $type->parent->name, $type->type_parameter->library, , $type->type_parameter->name );
1298 0           $opts_string .= $opts_indent . sprintf( 'type_constraint => do { %s; %s },', $requires, $ptype );
1299             }
1300             else {
1301 0           local $Type::Tiny::AvoidCallbacks = 1;
1302 0           local $Type::Tiny::SafePackage = '';
1303 0           $opts_string .= $opts_indent . 'type_constraint => do {';
1304 0           $opts_string .= $opts_indent . ' require Type::Tiny;';
1305 0           $opts_string .= $opts_indent . ' my $TYPE = Type::Tiny->new(';
1306 0           $opts_string .= $opts_indent . sprintf ' display_name => %s,', B::perlstring( $type->display_name );
1307 0           $opts_string .= $opts_indent . sprintf ' constraint => sub { %s },', $type->inline_check( '$_' );
1308 0           $opts_string .= $opts_indent . ' );';
1309 0 0         if ( $type->has_coercion ) {
1310 0           $opts_string .= $opts_indent . ' require Types::Standard;';
1311 0           $opts_string .= $opts_indent . ' $TYPE->coercion->add_type_coercions(';
1312 0           $opts_string .= $opts_indent . ' Types::Standard::Any(),';
1313 0           $opts_string .= $opts_indent . sprintf ' sub { %s },', $type->coercion->inline_coercion( '$_' );
1314 0           $opts_string .= $opts_indent . ' );';
1315 0           $opts_string .= $opts_indent . ' $TYPE->coercion->freeze;';
1316             }
1317 0           $opts_string .= $opts_indent . ' $TYPE;';
1318 0           $opts_string .= $opts_indent . '},';
1319             }
1320 0 0 0       if ( $type->has_coercion and $self->coerce ) {
1321 0           $opts_string .= $opts_indent . 'coerce => true,';
1322             }
1323             }
1324              
1325 0           for my $accessor ( qw/ reader writer accessor predicate clearer / ) {
1326 0           my $name = $self->_expand_name( $self->$accessor );
1327 0 0         defined $name or next;
1328 0           my $qname = $self->_q( $name );
1329 0           my $dfnctx = $self->definition_context_to_string( description => sprintf( '%s %s::%s', $accessor, $self->compiling_class->name, $name ) );
1330              
1331 0           $opts_string .= $opts_indent . sprintf( '%s => %s,', $accessor, $qname );
1332              
1333 0           $accessors_code .= sprintf <<'CODE', $accessor, $self->_q_name, $qname, $self->compiling_class->name, $name, $self->_q($self->compiling_class->name), $dfnctx, $self->_q_name;
1334             {
1335             my $ACCESSOR = Moose::Meta::Method::Accessor->new(
1336             accessor_type => '%s',
1337             attribute => $ATTR{%s},
1338             name => %s,
1339             body => \&%s::%s,
1340             package_name => %s,
1341             definition_context => %s,
1342             );
1343             $ATTR{%s}->associate_method( $ACCESSOR );
1344             $PACKAGE->add_method( $ACCESSOR->name, $ACCESSOR );
1345             }
1346             CODE
1347             }
1348              
1349 0           for my $accessor ( qw/ lvalue local_writer / ) {
1350 0           my $name = $self->_expand_name( $self->$accessor );
1351 0 0         defined $name or next;
1352 0           my $qname = $self->_q( $name );
1353              
1354 0           $accessors_code .= sprintf <<'CODE', $qname, $self->compiling_class->name, $name, $self->_q($self->compiling_class->name), $self->_q_name;
1355             {
1356             my $ACCESSOR = Moose::Meta::Method->_new(
1357             name => %s,
1358             body => \&%s::%s,
1359             package_name => %s,
1360             );
1361             $ATTR{%s}->associate_method( $ACCESSOR );
1362             $PACKAGE->add_method( $ACCESSOR->name, $ACCESSOR );
1363             }
1364             CODE
1365             }
1366              
1367 0 0         if ( $self->has_handles_via ) {
    0          
    0          
1368 0           my $h = $self->handles;
1369 0           for my $delegated ( sort keys %$h ) {
1370 0           my $name = $self->_expand_name( $delegated );
1371 0           my $qname = $self->_q( $name );
1372              
1373 0           $accessors_code .= sprintf <<'CODE', $qname, $self->compiling_class->name, $name, $self->_q($self->compiling_class->name), $self->_q_name;
1374             {
1375             my $DELEGATION = Moose::Meta::Method->_new(
1376             name => %s,
1377             body => \&%s::%s,
1378             package_name => %s,
1379             );
1380             $ATTR{%s}->associate_method( $DELEGATION );
1381             $PACKAGE->add_method( $DELEGATION->name, $DELEGATION );
1382             }
1383             CODE
1384             }
1385             }
1386             elsif ( ref $self->handles ) {
1387 0           my $h = $self->handles;
1388 0           my $hstring = '';
1389 0           for my $delegated ( sort keys %$h ) {
1390 0           my $name = $self->_expand_name( $delegated );
1391 0           my $qname = $self->_q( $name );
1392 0           my $target = $h->{$delegated};
1393 0           my $qtarget = $self->_q( $target );
1394 0           $hstring .= ", $qname => $qtarget";
1395              
1396 0           $accessors_code .= sprintf <<'CODE', $qname, $self->_q_name, $qtarget, $self->compiling_class->name, $name, $self->_q($self->compiling_class->name), $self->_q_name;
1397             {
1398             my $DELEGATION = Moose::Meta::Method::Delegation->new(
1399             name => %s,
1400             attribute => $ATTR{%s},
1401             delegate_to_method => %s,
1402             curried_arguments => [],
1403             body => \&%s::%s,
1404             package_name => %s,
1405             );
1406             $ATTR{%s}->associate_method( $DELEGATION );
1407             $PACKAGE->add_method( $DELEGATION->name, $DELEGATION );
1408             }
1409             CODE
1410             }
1411              
1412 0 0         if ( $hstring ) {
1413 0           $hstring =~ s/^, //;
1414 0           $opts_string .= $opts_indent . "handles => { $hstring },";
1415             }
1416             }
1417             elsif ( $self->has_handles ) {
1418 0           my %native_delegations = %{ $self->_compile_native_delegations };
  0            
1419 0           for my $method_name ( sort keys %native_delegations ) {
1420 0           my $qname = $self->_q( $method_name );
1421 0           $accessors_code .= sprintf <<'CODE', $qname, $self->compiling_class->name, $method_name, $self->_q($self->compiling_class->name), $self->_q_name;
1422             {
1423             my $DELEGATION = Moose::Meta::Method->_new(
1424             name => %s,
1425             body => \&%s::%s,
1426             package_name => %s,
1427             );
1428             $ATTR{%s}->associate_method( $DELEGATION );
1429             $PACKAGE->add_method( $DELEGATION->name, $DELEGATION );
1430             }
1431             CODE
1432             }
1433             }
1434              
1435             {
1436 0           my @aliases = $self->_all_aliases;
  0            
1437 0           for my $name ( sort @aliases ) {
1438 0           my $qname = $self->_q( $name );
1439              
1440 0           $accessors_code .= sprintf <<'CODE', $qname, $self->compiling_class->name, $name, $self->_q($self->compiling_class->name), $self->_q_name;
1441             {
1442             my $ALIAS = Moose::Meta::Method->_new(
1443             name => %s,
1444             body => \&%s::%s,
1445             package_name => %s,
1446             );
1447             $ATTR{%s}->associate_method( $ALIAS );
1448             $PACKAGE->add_method( $ALIAS->name, $ALIAS );
1449             }
1450             CODE
1451             }
1452             }
1453              
1454 0 0 0       if ( my $builder = $self->_expand_name( $self->builder ) ) {
    0          
    0          
    0          
1455 0           $opts_string .= $opts_indent . sprintf( 'builder => %s,', $self->_q( $builder ) );
1456             }
1457             elsif ( $self->has_inline_default or $self->has_reference_default ) {
1458 0           $opts_string .= $opts_indent . sprintf( 'default => sub { %s },', $self->_compile_default );
1459             }
1460             elsif ( $self->has_coderef_default ) {
1461 0           $opts_string .= $opts_indent . sprintf( 'default => %s,', $self->coderef_default_variable );
1462             }
1463             elsif ( $self->has_default ) {
1464 0           $opts_string .= $opts_indent . sprintf( 'default => %s,', $self->_compile_default );
1465             }
1466 0 0 0       if ( $self->has_default or $self->has_builder ) {
1467 0 0         $opts_string .= $opts_indent . sprintf( 'lazy => %s,', $self->lazy ? 'true' : 'false' );
1468             }
1469              
1470 0 0         if ( my $trigger = $self->_expand_name( $self->trigger ) ) {
1471 0           $opts_string .= $opts_indent . sprintf( 'trigger => sub { shift->%s( @_ ) },', $trigger );
1472             }
1473              
1474 0 0         if ( $self->has_documentation ) {
1475 0           $opts_string .= $opts_indent . sprintf( 'documentation => %s,', $self->_q( $self->documentation ) );
1476             }
1477              
1478 0 0         if ( not $self->compiling_class->isa( 'Mite::Class' ) ) {
1479 0           $accessors_code = sprintf "delete \$ATTR{%s}{original_options}{\$_} for qw( associated_role );\n",
1480             $self->_q_name;
1481             }
1482              
1483 0           $opts_string .= "\n";
1484 0           return sprintf <<'CODE', $self->_q_name, $self->compiling_class->_mop_attribute_metaclass, $self->_q_name, $opts_string, $accessors_code, $self->_q_name;
1485             $ATTR{%s} = %s->new( %s,%s);
1486             %sdo {
1487             no warnings 'redefine';
1488             local *Moose::Meta::Attribute::install_accessors = sub {};
1489             $PACKAGE->add_attribute( $ATTR{%s} );
1490             };
1491             CODE
1492             }
1493              
1494             1;