X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMouse%2FMeta%2FClass.pm;h=796872acb393f956b5c2a90cff9d7c57a1ba66d3;hb=50dc6ee5748409751a8e0ef57a0e7c93e2c48cb4;hp=ea7c8960c99d0888a239e76790c0bf54248070b2;hpb=306290e864ac23e5f1692c8495b0c173081a1ebb;p=gitmo%2FMouse.git diff --git a/lib/Mouse/Meta/Class.pm b/lib/Mouse/Meta/Class.pm index ea7c896..796872a 100644 --- a/lib/Mouse/Meta/Class.pm +++ b/lib/Mouse/Meta/Class.pm @@ -3,10 +3,23 @@ package Mouse::Meta::Class; use strict; use warnings; +use Scalar::Util 'blessed'; +use Carp 'confess'; + use MRO::Compat; +use Class::Method::Modifiers (); 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 +31,7 @@ do { sub new { my $class = shift; - my %args = @_; + my %args = @_; $args{attributes} = {}; $args{superclasses} = do { @@ -42,6 +55,17 @@ sub superclasses { @{ $self->{superclasses} }; } +sub add_method { + my $self = shift; + my $name = shift; + my $code = shift; + + my $pkg = $self->name; + + no strict 'refs'; + *{ $pkg . '::' . $name } = $code; +} + sub add_attribute { my $self = shift; my $attr = shift; @@ -49,11 +73,94 @@ 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; + +} + +sub make_immutable {} +sub is_immutable { 0 } + +sub attribute_metaclass { "Mouse::Meta::Class" } + +sub add_before_method_modifier { + my ($self, $name, $code) = @_; + Class::Method::Modifiers::_install_modifier( + $self->name, + 'before', + $name, + $code, + ); +} + +sub add_around_method_modifier { + my ($self, $name, $code) = @_; + Class::Method::Modifiers::_install_modifier( + $self->name, + 'around', + $name, + $code, + ); +} + +sub add_after_method_modifier { + my ($self, $name, $code) = @_; + Class::Method::Modifiers::_install_modifier( + $self->name, + 'after', + $name, + $code, + ); +} + 1; __END__ @@ -86,11 +193,20 @@ Gets (or sets) the list of superclasses of the owner class. Begins keeping track of the existing L for the owner class. +=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. +=head2 has_attribute Name -> Boool + +Returns whether we have a L with the given name. + =head2 get_attribute Name -> Mouse::Meta::Attribute | undef Returns the L with the given name. @@ -99,5 +215,14 @@ Returns the L with the given name. 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