Add built local::lib
[catagits/Gitalist.git] / local-lib5 / lib / perl5 / MooseX / Clone / Meta / Attribute / Trait / Clone.pm
CommitLineData
3fea05b9 1#!/usr/bin/perl
2
3package MooseX::Clone::Meta::Attribute::Trait::Clone;
4use Moose::Role;
5
6use Carp qw(croak);
7
8use namespace::clean -except => 'meta';
9
10with qw(MooseX::Clone::Meta::Attribute::Trait::Clone::Base);
11
12sub Moose::Meta::Attribute::Custom::Trait::Clone::register_implementation { __PACKAGE__ }
13
14has clone_only_objects => (
15 isa => "Bool",
16 is => "rw",
17 default => 0,
18);
19
20has clone_visitor => (
21 isa => "Data::Visitor",
22 is => "rw",
23 lazy_build => 1,
24);
25
26has clone_visitor_config => (
27 isa => "HashRef",
28 is => "ro",
29 default => sub { { } },
30);
31
32sub _build_clone_visitor {
33 my $self = shift;
34
35 require Data::Visitor::Callback;
36
37 Data::Visitor::Callback->new(
38 object => sub { $self->clone_object_value($_[1]) },
39 tied_as_objects => 1,
40 %{ $self->clone_visitor_config },
41 );
42}
43
44sub clone_value {
45 my ( $self, $target, $proto, @args ) = @_;
46
47 if ( $self->has_value($proto) ) {
48 my $clone = $self->clone_value_data( scalar($self->get_value($proto)), @args );
49
50 $self->set_value( $target, $clone );
51 } else {
52 my %args = @args;
53
54 if ( exists $args{init_arg} ) {
55 $self->set_value( $target, $args{init_arg} );
56 }
57 }
58}
59
60sub clone_value_data {
61 my ( $self, $value, @args ) = @_;
62
63 if ( blessed($value) ) {
64 return $self->clone_object_value($value, @args);
65 } else {
66 my %args = @args;
67
68 if ( exists $args{init_arg} ) {
69 return $args{init_arg};
70 } else {
71 unless ( $self->clone_only_objects ) {
72 return $self->clone_any_value($value, @args);
73 } else {
74 return $value;
75 }
76 }
77 }
78}
79
80sub clone_object_value {
81 my ( $self, $value, %args ) = @_;
82
83 if ( $value->can("clone") ) {
84 my @clone_args;
85
86 if ( exists $args{init_arg} ) {
87 my $init_arg = $args{init_arg};
88
89 if ( ref $init_arg ) {
90 if ( ref $init_arg eq 'HASH' ) { @clone_args = %$init_arg }
91 elsif ( ref $init_arg eq 'ARRAY' ) { @clone_args = @$init_arg }
92 else {
93 croak "Arguments to a sub clone should be given in a hash or array reference";
94 }
95 } else {
96 croak "Arguments to a sub clone should be given in a hash or array reference";
97 }
98 }
99
100 return $value->clone(@clone_args);
101 } else {
102 croak "Cannot recursively clone a retarded object $value (" . overload::StrVal($value) . ") in " . $args{attr}->name . ". Try something better.";
103 }
104}
105
106sub clone_any_value {
107 my ( $self, $value, %args ) = @_;
108 $self->clone_visitor->visit($value);
109}
110
111__PACKAGE__
112
113__END__
114
115=pod
116
117=encoding utf8
118
119=head1 NAME
120
121MooseX::Clone::Meta::Attribute::Trait::Clone - The L<Moose::Meta::Attribute>
122trait for deeply cloning attributes.
123
124=head1 SYNOPSIS
125
126 # see MooseX::Clone
127
128 has foo => (
129 traits => [qw(Clone)],
130 isa => "Something",
131 );
132
133 $object->clone; # will recursively call $object->foo->clone and set the value properly
134
135=head1 DESCRIPTION
136
137This meta attribute trait provides a C<clone_value> method, in the spirit of
138C<get_value> and C<set_value>. This allows clone methods such as the one in
139L<MooseX::Clone> to make use of this per-attribute cloning behavior.
140
141=head1 DERIVATION
142
143Deriving this role for your own cloning purposes is encouraged.
144
145This will allow your fine grained cloning semantics to interact with
146L<MooseX::Clone> in the Rightâ„¢ way.
147
148=head1 ATTRIBUTES
149
150=over 4
151
152=item clone_only_objects
153
154Whether or not L<Data::Visitor> should be used to clone arbitrary structures.
155Objects found in these structures will be cloned using L<clone_object_value>.
156
157If true then non object values will be copied over in shallow cloning semantics
158(shared reference).
159
160Defaults to false (all reference will be cloned).
161
162=item clone_visitor_config
163
164A hash ref used to construct C<clone_visitor>. Defaults to the empty ref.
165
166This can be used to alter the cloning behavior for non object values.
167
168=item clone_visitor
169
170The L<Data::Visitor::Callback> object that will be used to clone.
171
172It has an C<object> handler that delegates to C<clone_object_value> and sets
173C<tied_as_objects> to true in order to deeply clone tied structures while
174retaining magic.
175
176Only used if C<clone_only_objects> is false and the value of the attribute is
177not an object.
178
179=back
180
181=head1 METHODS
182
183=over 4
184
185=item clone_value $target, $proto, %args
186
187Clones the value the attribute encapsulates from C<$proto> into C<$target>.
188
189=item clone_value_data $value, %args
190
191Does the actual cloning of the value data by delegating to a C<clone> method on
192the object if any.
193
194If the object does not support a C<clone> method an error is thrown.
195
196If the value is not an object then it will not be cloned.
197
198In the future support for deep cloning of simple refs will be added too.
199
200=item clone_object_value $object, %args
201
202This is the actual workhorse of C<clone_value_data>.
203
204=item clone_any_value $value, %args
205
206Uses C<clone_visitor> to clone all non object values.
207
208Called from C<clone_value_data> if the value is not an object and
209C<clone_only_objects> is false.
210
211=back
212
213=cut