better definition context for native delegation methods
[gitmo/Moose.git] / lib / Moose / Meta / Method / Accessor / Native.pm
1 package Moose::Meta::Method::Accessor::Native;
2
3 use strict;
4 use warnings;
5
6 use Carp qw( confess );
7 use Scalar::Util qw( blessed weaken );
8
9 use Moose::Role;
10
11 around new => sub {
12     my $orig = shift;
13     my $class   = shift;
14     my %options = @_;
15
16     $options{curried_arguments} = []
17         unless exists $options{curried_arguments};
18
19     confess 'You must supply a curried_arguments which is an ARRAY reference'
20         unless $options{curried_arguments}
21             && ref($options{curried_arguments}) eq 'ARRAY';
22
23     my $attr_context = $options{attribute}->definition_context;
24     my $desc = 'native delegation method ';
25     $desc   .= $options{attribute}->associated_class->name;
26     $desc   .= '::' . $options{name};
27     $desc   .= " ($options{delegate_to_method})";
28     $desc   .= " of attribute " . $options{attribute}->name;
29     $options{definition_context} = {
30         %{ $attr_context || {} },
31         description => $desc,
32     };
33
34     $options{accessor_type} = 'native';
35
36     return $class->$orig(%options);
37 };
38
39 sub _new {
40     my $class = shift;
41     my $options = @_ == 1 ? $_[0] : {@_};
42
43     return bless $options, $class;
44 }
45
46 sub root_types { (shift)->{'root_types'} }
47
48 sub _initialize_body {
49     my $self = shift;
50
51     $self->{'body'} = $self->_compile_code( [$self->_generate_method] );
52
53     return;
54 }
55
56 sub _inline_curried_arguments {
57     my $self = shift;
58
59     return unless @{ $self->curried_arguments };
60
61     return 'unshift @_, @curried;';
62 }
63
64 sub _inline_check_argument_count {
65     my $self = shift;
66
67     my @code;
68
69     if (my $min = $self->_minimum_arguments) {
70         push @code, (
71             'if (@_ < ' . $min . ') {',
72                 $self->_inline_throw_error(
73                     sprintf(
74                         '"Cannot call %s without at least %s argument%s"',
75                         $self->delegate_to_method,
76                         $min,
77                         ($min == 1 ? '' : 's'),
78                     )
79                 ) . ';',
80             '}',
81         );
82     }
83
84     if (defined(my $max = $self->_maximum_arguments)) {
85         push @code, (
86             'if (@_ > ' . $max . ') {',
87                 $self->_inline_throw_error(
88                     sprintf(
89                         '"Cannot call %s with %s argument%s"',
90                         $self->delegate_to_method,
91                         $max ? "more than $max" : 'any',
92                         ($max == 1 ? '' : 's'),
93                     )
94                 ) . ';',
95             '}',
96         );
97     }
98
99     return @code;
100 }
101
102 sub _inline_return_value {
103     my $self = shift;
104     my ($slot_access, $for_writer) = @_;
105
106     return 'return ' . $self->_return_value($slot_access, $for_writer) . ';';
107 }
108
109 sub _minimum_arguments { 0 }
110 sub _maximum_arguments { undef }
111
112 override _get_value => sub {
113     my $self = shift;
114     my ($instance) = @_;
115
116     return $self->_slot_access_can_be_inlined
117         ? super()
118         : $instance . '->$reader';
119 };
120
121 override _inline_store_value => sub {
122     my $self = shift;
123     my ($instance, $value) = @_;
124
125     return $self->_slot_access_can_be_inlined
126         ? super()
127         : $instance . '->$writer(' . $value . ');';
128 };
129
130 override _eval_environment => sub {
131     my $self = shift;
132
133     my $env = super();
134
135     $env->{'@curried'} = $self->curried_arguments;
136
137     return $env if $self->_slot_access_can_be_inlined;
138
139     my $reader = $self->associated_attribute->get_read_method_ref;
140     $reader = $reader->body if blessed $reader;
141
142     $env->{'$reader'} = \$reader;
143
144     my $writer = $self->associated_attribute->get_write_method_ref;
145     $writer = $writer->body if blessed $writer;
146
147     $env->{'$writer'} = \$writer;
148
149     return $env;
150 };
151
152 sub _slot_access_can_be_inlined {
153     my $self = shift;
154
155     return $self->is_inline && $self->_instance_is_inlinable;
156 }
157
158 no Moose::Role;
159
160 1;