Add support for Type in native traits
[gitmo/Moose.git] / lib / Moose / Meta / Method / Accessor / Native / Collection.pm
CommitLineData
44babf1f 1package Moose::Meta::Method::Accessor::Native::Collection;
2
3use strict;
4use warnings;
5
8b9641b8 6use Moose::Role;
7
8requires qw( _adds_members );
9
53a4677c 10sub _inline_coerce_new_values {
7bf5e58d 11 my $self = shift;
12
53a4677c 13 return unless $self->associated_attribute->should_coerce;
7bf5e58d 14
53a4677c 15 return unless $self->_tc_member_type_can_coerce;
7bf5e58d 16
53a4677c 17 return (
ec02b571 18 '(' . $self->_new_members . ') = map { $member_coercion->($_) }',
53a4677c 19 $self->_new_members . ';',
20 );
21}
7bf5e58d 22
23sub _tc_member_type_can_coerce {
24 my $self = shift;
25
26 my $member_tc = $self->_tc_member_type;
27
28 return $member_tc && $member_tc->has_coercion;
29}
30
31sub _tc_member_type {
32 my $self = shift;
33
53a4677c 34 my $tc = $self->associated_attribute->type_constraint;
35 while ($tc) {
7bf5e58d 36 return $tc->type_parameter
37 if $tc->can('type_parameter');
53a4677c 38 $tc = $tc->parent;
7bf5e58d 39 }
40
41 return;
42}
43
6e50f7e9 44sub _writer_value_needs_copy {
44babf1f 45 my $self = shift;
46
47 return $self->_constraint_must_be_checked
48 && !$self->_check_new_members_only;
53a4677c 49}
44babf1f 50
53a4677c 51sub _inline_tc_code {
52 my $self = shift;
a619fc2f 53 my ($value, $tc, $coercion, $message, $is_lazy) = @_;
44babf1f 54
53a4677c 55 return unless $self->_constraint_must_be_checked;
44babf1f 56
53a4677c 57 if ($self->_check_new_members_only) {
58 return unless $self->_adds_members;
44babf1f 59
53a4677c 60 return $self->_inline_check_member_constraint($self->_new_members);
44babf1f 61 }
62 else {
53a4677c 63 return (
c40e4359 64 $self->_inline_check_coercion($value, $tc, $coercion, $is_lazy),
a619fc2f 65 $self->_inline_check_constraint($value, $tc, $message, $is_lazy),
53a4677c 66 );
44babf1f 67 }
53a4677c 68}
44babf1f 69
70sub _check_new_members_only {
71 my $self = shift;
72
73 my $attr = $self->associated_attribute;
74
75 my $tc = $attr->type_constraint;
76
77 # If we have a coercion, we could come up with an entirely new value after
78 # coercing, so we need to check everything,
79 return 0 if $attr->should_coerce && $tc->has_coercion;
80
81 # If the parent is our root type (ArrayRef, HashRef, etc), that means we
82 # can just check the new members of the collection, because we know that
83 # we will always be generating an appropriate collection type.
84 #
85 # However, if this type has its own constraint (it's Parameteriz_able_,
86 # not Paramet_erized_), we don't know what is being checked by the
87 # constraint, so we need to check the whole value, not just the members.
88 return 1
89 if $self->_is_root_type( $tc->parent )
d85da60f 90 && ( $tc->isa('Moose::Meta::TypeConstraint::Parameterized')
91 || $tc->isa('Type::Constraint::Parameterized') );
44babf1f 92
93 return 0;
94}
95
96sub _inline_check_member_constraint {
53a4677c 97 my $self = shift;
98 my ($new_value) = @_;
44babf1f 99
100 my $attr_name = $self->associated_attribute->name;
101
31056177 102 my $check
7c047a36 103 = $self->_tc_member_type->can_be_inlined
0e8cddd7 104 ? '! (' . $self->_tc_member_type->_inline_check('$new_val') . ')'
105 : ' !$member_tc->($new_val) ';
31056177 106
53a4677c 107 return (
0e8cddd7 108 'for my $new_val (' . $new_value . ') {',
31056177 109 "if ($check) {",
53a4677c 110 $self->_inline_throw_error(
111 '"A new member value for ' . $attr_name
ec02b571 112 . ' does not pass its type constraint because: "' . ' . '
113 . 'do { local $_ = $new_val; $member_message->($new_val) }',
0e8cddd7 114 'data => $new_val',
53a4677c 115 ) . ';',
116 '}',
117 '}',
118 );
44babf1f 119}
120
53a4677c 121sub _inline_get_old_value_for_trigger {
122 my $self = shift;
123 my ($instance, $old) = @_;
44babf1f 124
125 my $attr = $self->associated_attribute;
53a4677c 126 return unless $attr->has_trigger;
44babf1f 127
53a4677c 128 return (
1e2c801e 129 'my ' . $old . ' = ' . $self->_has_value($instance),
130 '? ' . $self->_copy_old_value($self->_get_value($instance)),
53a4677c 131 ': ();',
132 );
133}
44babf1f 134
8b9641b8 135around _eval_environment => sub {
44babf1f 136 my $orig = shift;
137 my $self = shift;
138
139 my $env = $self->$orig(@_);
140
7bf5e58d 141 my $member_tc = $self->_tc_member_type;
142
143 return $env unless $member_tc;
144
7bf5e58d 145 $env->{'$member_tc'} = \( $member_tc->_compiled_type_constraint );
ec02b571 146 $env->{'$member_coercion'} = \(
147 $member_tc->coercion->_compiled_type_coercion
148 ) if $member_tc->has_coercion;
149 $env->{'$member_message'} = \(
150 $member_tc->has_message
151 ? $member_tc->message
152 : $member_tc->_default_message
153 );
44babf1f 154
0e8cddd7 155 my $tc_env = $member_tc->inline_environment();
156
157 $env = { %{$env}, %{$tc_env} };
158
44babf1f 159 return $env;
8b9641b8 160};
44babf1f 161
162no Moose::Role;
163
1641;