File Coverage

blib/lib/MooX/Thunking.pm
Criterion Covered Total %
statement 50 50 100.0
branch 12 16 75.0
condition n/a
subroutine 13 13 100.0
pod n/a
total 75 79 94.9


line stmt bran cond sub pod time code
1             package MooX::Thunking;
2              
3             our $VERSION = '0.08';
4              
5             # this bit would be MooX::Utils but without initial _ on func name
6 4     4   280469 use strict;
  4         16  
  4         87  
7 4     4   17 use warnings;
  4         7  
  4         71  
8 4     4   413 use Moo ();
  4         2495  
  4         47  
9 4     4   1210 use Moo::Role ();
  4         20787  
  4         87  
10 4     4   23 use Carp qw(croak);
  4         8  
  4         563  
11             #use base qw(Exporter);
12             #our @EXPORT = qw(override_function);
13             sub _override_function {
14 4     4   14 my ($target, $name, $func) = @_;
15 4 50       56 my $orig = $target->can($name) or croak "Override '$target\::$name': not found";
16 4 100       32 my $install_tracked = Moo::Role->is_role($target) ? \&Moo::Role::_install_tracked : \&Moo::_install_tracked;
17 4     4   186 $install_tracked->($target, $name, sub { $func->($orig, @_) });
  4     4   97087  
18             }
19             # end MooX::Utils;
20              
21 4     4   1768 use Types::TypeTiny -all;
  4         11025  
  4         18  
22 4     4   20111 use Type::Utils -all;
  4         78620  
  4         29  
23 4     4   13048 use Class::Method::Modifiers qw(install_modifier);
  4         5343  
  4         1037  
24             sub import {
25 4     4   46 my $target = scalar caller;
26             _override_function($target, 'has', sub {
27 4     4   23 my ($orig, $namespec, %opts) = @_;
28 4 50       19 $orig->($namespec, %opts), return if $opts{is} ne 'thunked';
29 4         29 $opts{is} = 'rwp';
30 4 100       15 $opts{isa} = union [ CodeLike, $opts{isa} ] if $opts{isa};
31 4         7036 $orig->($namespec, %opts); # so we have method to modify
32 4 100       70555 for my $name (ref $namespec ? @$namespec : $namespec) {
33 5         191 my $resolved_name = "_${name}_resolved";
34 5         18 $orig->($resolved_name, is => 'rw'); # cache whether resolved
35             install_modifier $target, 'before', $name => sub {
36 9         39542 my $self = shift;
37 9 50       29 return if @_; # attempt at setting, hand to auto
38 9 50       59 return if $self->$resolved_name; # already resolved
39 9         26 $self->$resolved_name(1);
40 9         18 local $@;
41 9 100       16 return if !eval { CodeLike->($self->{$name}); 1 }; # not a thunk
  9         36  
  6         2490  
42 6         17 my $setter = "_set_$name";
43 6         25 $self->$setter($self->{$name}->());
44 5         1150 };
45             }
46 4         29 });
47             }
48              
49             =head1 NAME
50              
51             MooX::Thunking - Allow Moo attributes to be "thunked"
52              
53             =head1 SYNOPSIS
54              
55             package Thunking;
56             use Moo;
57             use MooX::Thunking;
58             use Types::TypeTiny -all;
59             use Types::Standard -all;
60             has children => (
61             is => 'thunked',
62             isa => ArrayRef[InstanceOf['Thunking']],
63             required => 1,
64             );
65              
66             package main;
67             my $obj;
68             $obj = Thunking->new(children => sub { [$obj] });
69              
70             =head1 DESCRIPTION
71              
72             This is a L extension. It allows another value for the C
73             parameter to L: "thunked". If used, this will allow you to
74             transparently provide either a real value for the attribute, or a
75             L that when called will return such a real
76             value.
77              
78             Note that in earlier versions of this module (up to 0.06), any C
79             had to pass a C. This is now taken care of by this module. It
80             will continue to do the right thing if no C is supplied.
81              
82             =head1 AUTHOR
83              
84             Ed J
85              
86             =head1 LICENCE
87              
88             The same terms as Perl itself.
89              
90             =cut
91              
92             1;