From: Yuval Kogman Date: Wed, 18 Jun 2008 07:17:09 +0000 (+0000) Subject: clone_{object,instance} X-Git-Tag: 0.19~288 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=7a59f4e85d2dadb67b6ce3112a9066cb8696611a;hp=ddd4992c86d379ec9b013bdbb6e070d939ee18f0;p=gitmo%2FMouse.git clone_{object,instance} --- diff --git a/lib/Mouse/Meta/Class.pm b/lib/Mouse/Meta/Class.pm index 0d70166..6c94c93 100644 --- a/lib/Mouse/Meta/Class.pm +++ b/lib/Mouse/Meta/Class.pm @@ -4,6 +4,7 @@ use strict; use warnings; use Scalar::Util 'blessed'; +use Carp 'confess'; use MRO::Compat; @@ -83,6 +84,37 @@ sub get_attribute { $_[0]->{attributes}->{$_[1]} } sub linearized_isa { @{ mro::get_linear_isa($_[0]->name) } } +sub clone_object { + my $class = shift; + my $instance = shift; + + (blessed($instance) && $instance->isa($class->name)) + || confess "You must pass an instance ($instance) of the metaclass (" . $class->name . ")"; + + $class->clone_instance($instance, @_); +} + +sub clone_instance { + my ($class, $instance, %params) = @_; + + (blessed($instance)) + || confess "You can only clone instances, \$self is not a blessed instance"; + + my $clone = bless { %$instance }, ref $instance; + + foreach my $attr ($class->compute_all_applicable_attributes()) { + if ( defined( my $init_arg = $attr->init_arg ) ) { + if (exists $params{$init_arg}) { + $clone->{ $attr->name } = $params{$init_arg}; + } + } + } + + return $clone; + +} + + 1; __END__ diff --git a/t/031-clone.t b/t/031-clone.t new file mode 100644 index 0000000..44b9ce0 --- /dev/null +++ b/t/031-clone.t @@ -0,0 +1,38 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use Test::More 'no_plan'; + +{ + package Foo; + use Mouse; + + has foo => ( + isa => "Str", + is => "rw", + default => "foo", + ); + + has bar => ( + isa => "ArrayRef", + is => "rw", + ); + + sub clone { + my ( $self, @args ) = @_; + $self->meta->clone_object( $self, @args ); + } +} + +my $foo = Foo->new( bar => [ 1, 2, 3 ] ); + +is( $foo->foo, "foo", "attr 1", ); +is_deeply( $foo->bar, [ 1 .. 3 ], "attr 2" ); + +my $clone = $foo->clone( foo => "dancing" ); + +is( $clone->foo, "dancing", "overridden attr" ); +is_deeply( $clone->bar, [ 1 .. 3 ], "clone attr" ); +