File Coverage

blib/lib/MooX/Thunking.pm
Criterion Covered Total %
statement 45 45 100.0
branch 10 14 71.4
condition n/a
subroutine 12 12 100.0
pod n/a
total 67 71 94.3


line stmt bran cond sub pod time code
1             package MooX::Thunking;
2              
3             our $VERSION = '0.06';
4              
5             # this bit would be MooX::Utils but without initial _ on func name
6 3     3   188878 use strict;
  3         6  
  3         68  
7 3     3   13 use warnings;
  3         4  
  3         54  
8 3     3   291 use Moo ();
  3         1980  
  3         42  
9 3     3   475 use Moo::Role ();
  3         11599  
  3         58  
10 3     3   15 use Carp qw(croak);
  3         6  
  3         367  
11             #use base qw(Exporter);
12             #our @EXPORT = qw(override_function);
13             sub _override_function {
14 3     3   17 my ($target, $name, $func) = @_;
15 3 50       34 my $orig = $target->can($name) or croak "Override '$target\::$name': not found";
16 3 100       25 my $install_tracked = Moo::Role->is_role($target) ? \&Moo::Role::_install_tracked : \&Moo::_install_tracked;
17 3     3   100 $install_tracked->($target, $name, sub { $func->($orig, @_) });
  3     3   112943  
18             }
19             # end MooX::Utils;
20              
21 3     3   801 use Types::TypeTiny -all;
  3         6099  
  3         11  
22 3     3   10186 use Class::Method::Modifiers qw(install_modifier);
  3         3588  
  3         612  
23             sub import {
24 3     3   26 my $target = scalar caller;
25             _override_function($target, 'has', sub {
26 3     3   16 my ($orig, $namespec, %opts) = @_;
27 3 50       14 $orig->($namespec, %opts), return if $opts{is} ne 'thunked';
28 3         8 $opts{is} = 'rwp';
29 3         17 $orig->($namespec, %opts); # so we have method to modify
30 3 100       45042 for my $name (ref $namespec ? @$namespec : $namespec) {
31 4         181 my $resolved_name = "_${name}_resolved";
32 4         13 $orig->($resolved_name, is => 'rw'); # cache whether resolved
33             install_modifier $target, 'before', $name => sub {
34 7         32098 my $self = shift;
35 7 50       26 return if @_; # attempt at setting, hand to auto
36 7 50       28 return if $self->$resolved_name; # already resolved
37 7         20 $self->$resolved_name(1);
38 7 100       10 return if !eval { CodeLike->($self->{$name}); 1 }; # not a thunk
  7         28  
  5         1748  
39 5         15 my $setter = "_set_$name";
40 5         17 $self->$setter($self->{$name}->());
41 4         926 };
42             }
43 3         18 });
44             }
45              
46             =head1 NAME
47              
48             MooX::Thunking - Allow Moo attributes to be "thunked"
49              
50             =head1 SYNOPSIS
51              
52             package Thunking;
53             use Moo;
54             use MooX::Thunking;
55             use Types::TypeTiny -all;
56             use Types::Standard -all;
57             has children => (
58             is => 'thunked',
59             isa => CodeLike | ArrayRef[InstanceOf['Thunking']],
60             required => 1,
61             );
62              
63             package main;
64             my $obj;
65             $obj = Thunking->new(children => sub { [$obj] });
66              
67             =head1 DESCRIPTION
68              
69             This is a L extension. It allows another value for the C
70             parameter to L: "thunked". If used, this will allow you to
71             transparently provide either a real value for the attribute, or a
72             L that when called will return such a real
73             value.
74              
75             =head1 AUTHOR
76              
77             Ed J
78              
79             =head1 LICENCE
80              
81             The same terms as Perl itself.
82              
83             =cut
84              
85             1;