File Coverage

blib/lib/MooX/Thunking.pm
Criterion Covered Total %
statement 49 49 100.0
branch 12 16 75.0
condition n/a
subroutine 13 13 100.0
pod n/a
total 74 78 94.8


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