Commit | Line | Data |
44babf1f |
1 | package Moose::Meta::Method::Accessor::Native::Collection; |
2 | |
3 | use strict; |
4 | use warnings; |
5 | |
8b9641b8 |
6 | use Moose::Role; |
7 | |
8 | requires qw( _adds_members ); |
9 | |
53a4677c |
10 | sub _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 ( |
18 | '(' . $self->_new_members . ') = map { $member_tc_obj->coerce($_) }', |
19 | $self->_new_members . ';', |
20 | ); |
21 | } |
7bf5e58d |
22 | |
23 | sub _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 | |
31 | sub _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 |
44 | sub _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 |
51 | sub _inline_tc_code { |
52 | my $self = shift; |
44babf1f |
53 | |
53a4677c |
54 | return unless $self->_constraint_must_be_checked; |
44babf1f |
55 | |
53a4677c |
56 | if ($self->_check_new_members_only) { |
57 | return unless $self->_adds_members; |
44babf1f |
58 | |
53a4677c |
59 | return $self->_inline_check_member_constraint($self->_new_members); |
44babf1f |
60 | } |
61 | else { |
53a4677c |
62 | return ( |
ec86bdff |
63 | $self->_inline_check_coercion(@_), |
64 | $self->_inline_check_constraint(@_), |
53a4677c |
65 | ); |
44babf1f |
66 | } |
53a4677c |
67 | } |
44babf1f |
68 | |
69 | sub _check_new_members_only { |
70 | my $self = shift; |
71 | |
72 | my $attr = $self->associated_attribute; |
73 | |
74 | my $tc = $attr->type_constraint; |
75 | |
76 | # If we have a coercion, we could come up with an entirely new value after |
77 | # coercing, so we need to check everything, |
78 | return 0 if $attr->should_coerce && $tc->has_coercion; |
79 | |
80 | # If the parent is our root type (ArrayRef, HashRef, etc), that means we |
81 | # can just check the new members of the collection, because we know that |
82 | # we will always be generating an appropriate collection type. |
83 | # |
84 | # However, if this type has its own constraint (it's Parameteriz_able_, |
85 | # not Paramet_erized_), we don't know what is being checked by the |
86 | # constraint, so we need to check the whole value, not just the members. |
87 | return 1 |
88 | if $self->_is_root_type( $tc->parent ) |
89 | && $tc->isa('Moose::Meta::TypeConstraint::Parameterized'); |
90 | |
91 | return 0; |
92 | } |
93 | |
94 | sub _inline_check_member_constraint { |
53a4677c |
95 | my $self = shift; |
96 | my ($new_value) = @_; |
44babf1f |
97 | |
98 | my $attr_name = $self->associated_attribute->name; |
99 | |
31056177 |
100 | my $check |
7c047a36 |
101 | = $self->_tc_member_type->can_be_inlined |
31056177 |
102 | ? '! (' . $self->_tc_member_type->_inline_check('$_') . ')' |
103 | : ' !$member_tc->($_) '; |
104 | |
53a4677c |
105 | return ( |
106 | 'for (' . $new_value . ') {', |
31056177 |
107 | "if ($check) {", |
53a4677c |
108 | $self->_inline_throw_error( |
109 | '"A new member value for ' . $attr_name |
110 | . ' does not pass its type constraint because: "' |
3a4e6199 |
111 | . ' . $member_tc_obj->get_message($_)', |
53a4677c |
112 | 'data => $_', |
113 | ) . ';', |
114 | '}', |
115 | '}', |
116 | ); |
44babf1f |
117 | } |
118 | |
53a4677c |
119 | sub _inline_get_old_value_for_trigger { |
120 | my $self = shift; |
121 | my ($instance, $old) = @_; |
44babf1f |
122 | |
123 | my $attr = $self->associated_attribute; |
53a4677c |
124 | return unless $attr->has_trigger; |
44babf1f |
125 | |
53a4677c |
126 | return ( |
1e2c801e |
127 | 'my ' . $old . ' = ' . $self->_has_value($instance), |
128 | '? ' . $self->_copy_old_value($self->_get_value($instance)), |
53a4677c |
129 | ': ();', |
130 | ); |
131 | } |
44babf1f |
132 | |
8b9641b8 |
133 | around _eval_environment => sub { |
44babf1f |
134 | my $orig = shift; |
135 | my $self = shift; |
136 | |
137 | my $env = $self->$orig(@_); |
138 | |
7bf5e58d |
139 | my $member_tc = $self->_tc_member_type; |
140 | |
141 | return $env unless $member_tc; |
142 | |
143 | $env->{'$member_tc_obj'} = \($member_tc); |
44babf1f |
144 | |
7bf5e58d |
145 | $env->{'$member_tc'} = \( $member_tc->_compiled_type_constraint ); |
44babf1f |
146 | |
147 | return $env; |
8b9641b8 |
148 | }; |
44babf1f |
149 | |
150 | no Moose::Role; |
151 | |
152 | 1; |