X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMouse%2FMeta%2FClass.pm;h=bf3276ae56227949c947370441bf7b36ccac217b;hb=181502b9e199623db8915eed96ad5f7f2c478835;hp=c43c12d44e2974e01e48e1c019aefd99514f32fd;hpb=58af95b87869e95b132806405054324491903fa1;p=gitmo%2FMouse.git diff --git a/lib/Mouse/Meta/Class.pm b/lib/Mouse/Meta/Class.pm index c43c12d..bf3276a 100644 --- a/lib/Mouse/Meta/Class.pm +++ b/lib/Mouse/Meta/Class.pm @@ -1,12 +1,24 @@ #!/usr/bin/env perl -package Mouse::Class; +package Mouse::Meta::Class; use strict; use warnings; +use Scalar::Util 'blessed'; +use Carp 'confess'; + use MRO::Compat; do { my %METACLASS_CACHE; + + # because Mouse doesn't introspect existing classes, we're forced to + # only pay attention to other Mouse classes + sub _metaclass_cache { + my $class = shift; + my $name = shift; + return $METACLASS_CACHE{$name}; + } + sub initialize { my $class = shift; my $name = shift; @@ -18,7 +30,7 @@ do { sub new { my $class = shift; - my %args = @_; + my %args = @_; $args{attributes} = {}; $args{superclasses} = do { @@ -49,29 +61,78 @@ sub add_attribute { $self->{'attributes'}{$attr->name} = $attr; } +sub compute_all_applicable_attributes { + my $self = shift; + my (@attr, %seen); + + for my $class ($self->linearized_isa) { + my $meta = $self->_metaclass_cache($class) + or next; + + for my $name (keys %{ $meta->get_attribute_map }) { + next if $seen{$name}++; + push @attr, $meta->get_attribute($name); + } + } + + return @attr; +} + sub get_attribute_map { $_[0]->{attributes} } +sub has_attribute { exists $_[0]->{attributes}->{$_[1]} } 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 of the metaclass (" . $class->name . "), not ($instance)"; + + $class->clone_instance($instance, @_); +} + +sub clone_instance { + my ($class, $instance, %params) = @_; + + (blessed($instance)) + || confess "You can only clone instances, ($instance) 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__ =head1 NAME -Mouse::Class - hook into the Mouse MOP +Mouse::Meta::Class - hook into the Mouse MOP =head1 METHODS -=head2 initialize ClassName -> Mouse::Class +=head2 initialize ClassName -> Mouse::Meta::Class -Finds or creates a Mouse::Class instance for the given ClassName. Only one -instance should exist for a given class. +Finds or creates a Mouse::Meta::Class instance for the given ClassName. Only +one instance should exist for a given class. -=head2 new %args -> Mouse::Class +=head2 new %args -> Mouse::Meta::Class -Creates a new Mouse::Class. Don't call this directly. +Creates a new Mouse::Meta::Class. Don't call this directly. =head2 name -> ClassName @@ -81,22 +142,41 @@ Returns the name of the owner class. Gets (or sets) the list of superclasses of the owner class. -=head2 add_attribute Mouse::Attribute +=head2 add_attribute Mouse::Meta::Attribute -Begins keeping track of the existing L for the owner class. +Begins keeping track of the existing L for the owner +class. -=head2 get_attribute_map -> { name => Mouse::Attribute } +=head2 compute_all_applicable_attributes -> (Mouse::Meta::Attribute) + +Returns the list of all L instances associated with +this class and its superclasses. + +=head2 get_attribute_map -> { name => Mouse::Meta::Attribute } Returns a mapping of attribute names to their corresponding -L objects. +L objects. + +=head2 has_attribute Name -> Boool + +Returns whether we have a L with the given name. -=head2 get_attribute Name -> Mouse::Attribute | undef +=head2 get_attribute Name -> Mouse::Meta::Attribute | undef -Returns the L with the given name. +Returns the L with the given name. =head2 linearized_isa -> [ClassNames] Returns the list of classes in method dispatch order, with duplicates removed. +=head2 clone_object Instance -> Instance + +Clones the given C which must be an instance governed by this +metaclass. + +=head2 clone_instance Instance, Parameters -> Instance + +Clones the given C and sets any additional parameters. + =cut