From: gfx Date: Tue, 27 Oct 2009 03:53:40 +0000 (+0900) Subject: Move add_method into XS X-Git-Tag: 0.40_02~22 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=3e44140bf0332cf0e44055fd76c2ba43cd898161;p=gitmo%2FMouse.git Move add_method into XS --- diff --git a/lib/Mouse/Meta/Module.pm b/lib/Mouse/Meta/Module.pm index 9dbe85d..df1f0bd 100755 --- a/lib/Mouse/Meta/Module.pm +++ b/lib/Mouse/Meta/Module.pm @@ -69,28 +69,6 @@ sub get_attribute { $_[0]->{attributes}->{$_[1]} } sub get_attribute_list{ keys %{$_[0]->{attributes}} } sub remove_attribute { delete $_[0]->{attributes}->{$_[1]} } -sub add_method { - my($self, $name, $code) = @_; - - if(!defined $name){ - $self->throw_error('You must pass a defined name'); - } - if(!defined $code){ - $self->throw_error('You must pass a defined code'); - } - - if(ref($code) ne 'CODE'){ - $code = \&{$code}; # coerce - } - - $self->{methods}->{$name} = $code; # Moose stores meta object here. - - my $pkg = $self->name; - no strict 'refs'; - no warnings 'redefine', 'once'; - *{ $pkg . '::' . $name } = $code; -} - # XXX: for backward compatibility my %foreign = map{ $_ => undef } qw( Mouse Mouse::Role Mouse::Util Mouse::Util::TypeConstraints @@ -104,6 +82,8 @@ sub _code_is_mine{ return !exists $foreign{$package}; } +sub add_method; + sub has_method { my($self, $method_name) = @_; diff --git a/lib/Mouse/PurePerl.pm b/lib/Mouse/PurePerl.pm index b60721e..ede54ca 100644 --- a/lib/Mouse/PurePerl.pm +++ b/lib/Mouse/PurePerl.pm @@ -134,6 +134,30 @@ sub namespace{ return \%{ $name . '::' }; } +sub add_method { + my($self, $name, $code) = @_; + + if(!defined $name){ + $self->throw_error('You must pass a defined name'); + } + if(!defined $code){ + $self->throw_error('You must pass a defined code'); + } + + if(ref($code) ne 'CODE'){ + $code = \&{$code}; # coerce + } + + $self->{methods}->{$name} = $code; # Moose stores meta object here. + + my $pkg = $self->name; + no strict 'refs'; + no warnings 'redefine', 'once'; + *{ $pkg . '::' . $name } = $code; + return; +} + + package Mouse::Meta::Class; diff --git a/xs-src/Mouse.xs b/xs-src/Mouse.xs index c34ad16..4ab4848 100644 --- a/xs-src/Mouse.xs +++ b/xs-src/Mouse.xs @@ -2,6 +2,7 @@ SV* mouse_package; SV* mouse_namespace; +SV* mouse_methods; MODULE = Mouse PACKAGE = Mouse::Util @@ -10,6 +11,8 @@ PROTOTYPES: DISABLE BOOT: mouse_package = newSVpvs_share("package"); mouse_namespace = newSVpvs_share("namespace"); + mouse_methods = newSVpvs_share("methods"); + MOUSE_CALL_BOOT(Mouse__Util__TypeConstraints); @@ -95,13 +98,68 @@ CODE: { SV* const package = mouse_instance_get_slot(aTHX_ self, mouse_package); if(!(package && SvOK(package))){ - croak("No package name"); + croak("No package name defined"); } RETVAL = gv_stashsv(package, GV_ADDMULTI); } OUTPUT: RETVAL +# ignore extra arguments for extensibility +void +add_method(SV* self, SV* name, SV* code, ...) +CODE: +{ + SV* const package = mouse_instance_get_slot(self, mouse_package); /* $self->{package} */ + SV* const methods = mouse_instance_get_slot(self, mouse_methods); /* $self->{methods} */ + GV* gv; + SV* code_ref; + + if(!(package && SvOK(package))){ + croak("No package name defined"); + } + + SvGETMAGIC(name); + SvGETMAGIC(code); + + if(!SvOK(name)){ + mouse_throw_error(self, NULL, "You must define a method name"); + } + if(!SvROK(code)){ + mouse_throw_error(self, NULL, "You must define a CODE reference"); + } + + code_ref = code; + if(SvTYPE(SvRV(code_ref)) != SVt_PVCV){ + SV* sv = code_ref; /* used in tryAMAGICunDEREF */ + SV** sp = &sv; /* used in tryAMAGICunDEREF */ + tryAMAGICunDEREF(to_cv); /* try \&{$code} */ + if(SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVCV){ + mouse_throw_error(self, NULL, "Not a CODE reference"); + } + code_ref = sv; + } + + /* *{$package . '::' . $name} -> *gv */ + gv = gv_fetchpv(form("%"SVf"::%"SVf, package, name), GV_ADDMULTI, SVt_PVCV); + if(GvCVu(gv)){ /* delete *slot{gv} to work around "redefine" warning */ + SvREFCNT_dec(GvCV(gv)); + GvCV(gv) = NULL; + } + sv_setsv_mg((SV*)gv, code_ref); /* *gv = $code_ref */ + + mouse_instance_set_slot(methods, name, code); /* $self->{methods}{$name} = $code */ + + /* TODO: name the CODE ref if it's anonymous */ + //code_entity = (CV*)SvRV(code_ref); + //if(CvANON(code_entity) + // && CvGV(code_entity) /* a cv under construction has no gv */ ){ + + // CvGV(code_entity) = gv; + // CvANON_off(code_entity); + //} +} + MODULE = Mouse PACKAGE = Mouse::Meta::Class BOOT: