File Coverage

lib/MouseX/AttributeHelpers/Base.pm
Criterion Covered Total %
statement 19 20 95.0
branch n/a
condition n/a
subroutine 12 13 92.3
pod 2 2 100.0
total 33 35 94.2


line stmt bran cond sub pod time code
1             package MouseX::AttributeHelpers::Base;
2 28     54   82744 use Mouse;
  28         139  
  28         186  
3              
4             extends 'Mouse::Meta::Attribute';
5              
6             has 'method_constructors' => (
7             is => 'ro',
8             isa => 'HashRef',
9             lazy => 1,
10             default => sub { +{} },
11             );
12              
13             around 'install_accessors' => sub {
14             my ($next, $attr, @args) = @_;
15              
16             $attr->$next(@args);
17              
18             my $metaclass = $attr->associated_class;
19             my $name = $attr->name;
20             my $constructors = $attr->method_constructors;
21              
22             # curries
23             my %curries = %{ $attr->{curries} || {} };
24             while (my ($key, $curry) = each %curries) {
25             next unless my $constructor = $constructors->{$key};
26              
27             my $code = $constructor->($attr, $name);
28              
29             while (my ($aliased, $args) = each %$curry) {
30             if ($metaclass->has_method($aliased)) {
31             my $classname = $metaclass->name;
32             $attr->throw_error("The method ($aliased) already exists in class ($classname)");
33             }
34              
35             my $method = do {
36             if (ref $args eq 'ARRAY') {
37             $attr->_make_curry($code, @$args);
38             }
39             elsif (ref $args eq 'CODE') {
40             $attr->_make_curry_with_sub($code, $args);
41             }
42             else {
43             $attr->throw_error("curries parameter must be ref type HASH or CODE");
44             }
45             };
46              
47             $metaclass->add_method($aliased => $method);
48             $attr->associate_method($aliased);
49             }
50             }
51              
52             # provides
53             my %provides = %{ $attr->{provides} || {} };
54             while (my ($key, $aliased) = each %provides) {
55             next unless my $constructor = $constructors->{$key};
56              
57             if ($metaclass->has_method($aliased)) {
58             my $classname = $metaclass->name;
59             $attr->throw_error("The method ($aliased) already exists in class ($classname)");
60             }
61              
62             $metaclass->add_method($aliased => $constructor->($attr, $name));
63             $attr->associate_method($aliased);
64             }
65              
66             return;
67             };
68              
69             around '_process_options' => sub {
70             my ($next, $class, $name, $args) = @_;
71              
72             $args->{is} = 'rw' unless exists $args->{is};
73             $args->{isa} = $class->helper_type unless exists $args->{isa};
74              
75             unless (exists $args->{default} or exists $args->{builder} or exists $args->{lazy_build}) {
76             $args->{default} = $class->helper_default if defined $class->helper_default;
77             }
78              
79             $class->$next($name, $args);
80             return;
81             };
82              
83 0     0 1 0 sub helper_type {}
84 3     3 1 9 sub helper_default {}
85              
86             sub _make_curry {
87 46     46   71 my $self = shift;
88 46         57 my $code = shift;
89 46         78 my @args = @_;
90             return sub {
91 47     47   4870 my $self = shift;
        40      
        49      
        69      
        38      
        8      
92 47         194 $code->($self, @args, @_);
93 46         236 };
94             }
95              
96             sub _make_curry_with_sub {
97 3     3   5 my $self = shift;
98 3         6 my $body = shift;
99 3         3 my $code = shift;
100             return sub {
101 3     3   7 my $self = shift;
102 3         15 $code->($self, $body, @_);
103 3         12 };
104             }
105              
106             # Mouse does not support proper imetaclass constructor replacement,
107             # so we must set inline_constructor false
108 28     28   57508 no Mouse;
  28         63  
  28         184  
109             __PACKAGE__->meta->make_immutable(inline_constructor => 0);
110             __END__