Merge 'trunk' into 'method_generation_cleanup'
Matt S Trout [Fri, 12 Dec 2008 08:26:36 +0000 (08:26 +0000)]
r26247@agaton (orig r6868):  rafl | 2008-12-05 06:19:54 +0000
Factor a c function doing all the hard work out of get_all_package_symbols.
r26248@agaton (orig r6869):  rafl | 2008-12-05 06:20:10 +0000
Make get_all_package_symbols return a hashref in scalar context.

Also deprecate usage in list context with a warning.
r26249@agaton (orig r6870):  rafl | 2008-12-05 06:20:19 +0000
Factor out a c version of get_code_info. Make get_method_map use that and the c
version of get_all_package_symbols.
r26250@agaton (orig r6871):  rafl | 2008-12-05 06:20:28 +0000
Don't check if the xs version of get_method_map is called as a class method.

The pure perl version doesn't do that either.
r26251@agaton (orig r6872):  rafl | 2008-12-05 06:20:37 +0000
A few simplifications to xs get_method_map.
r26252@agaton (orig r6873):  rafl | 2008-12-05 06:20:45 +0000
Make the c get_code_info static.
r26253@agaton (orig r6874):  rafl | 2008-12-05 06:20:54 +0000
use style; in MOP.xs.
r26254@agaton (orig r6875):  rafl | 2008-12-05 06:21:02 +0000
Fail if hv_store fails.
r26255@agaton (orig r6876):  rafl | 2008-12-05 06:28:17 +0000
get_method_map already is xsified.
r26256@agaton (orig r6877):  rafl | 2008-12-05 06:39:33 +0000
0.71_01 is already released. Move changelog entries for unreleased things to 0.72.
r26257@agaton (orig r6878):  rafl | 2008-12-05 06:39:42 +0000
Changelogging.
r26277@agaton (orig r6898):  autarch | 2008-12-05 19:21:07 +0000
bump version to 0.71_02 and update Changes
r26279@agaton (orig r6900):  autarch | 2008-12-05 19:23:55 +0000
add typemap to MANIFEST
r26283@agaton (orig r6904):  rafl | 2008-12-05 19:57:17 +0000
Tell ppport.h that we need newRV_noinc.
r26284@agaton (orig r6905):  rafl | 2008-12-05 20:35:57 +0000
Fix a few more style issues in MOP.xs.
r26536@agaton (orig r6927):  sartak | 2008-12-07 01:31:27 +0000
 r76628@onn:  sartak | 2008-12-06 20:30:24 -0500
 Pass options to Class::MOP::Package->_new (fixes failing Moose tests)

r26537@agaton (orig r6928):  sartak | 2008-12-07 01:59:43 +0000
 r76631@onn:  sartak | 2008-12-06 20:58:53 -0500
 Changelog entry

r26538@agaton (orig r6929):  sartak | 2008-12-07 02:03:21 +0000
 r76632@onn:  sartak | 2008-12-06 20:59:23 -0500
 Rename the test class from "Base" because case insensitive file systems try to subclass 'base'. Whee.

r26558@agaton (orig r6949):  autarch | 2008-12-07 18:47:04 +0000
No, Sartak, you cannot retroactively add code to a released tarball ;)

r26564@agaton (orig r6955):  sartak | 2008-12-08 01:08:40 +0000
 r76668@onn:  sartak | 2008-12-07 20:07:27 -0500
 Doc fix for CMOP::Method from sorear

r26565@agaton (orig r6956):  sartak | 2008-12-08 01:09:04 +0000
 r76670@onn:  sartak | 2008-12-07 20:08:30 -0500
 Put this change under the correct version

r26577@agaton (orig r6968):  autarch | 2008-12-08 14:49:13 +0000
Very small grammar tweak.

r26578@agaton (orig r6969):  autarch | 2008-12-08 14:49:52 +0000
Clarify change

r26584@agaton (orig r6975):  autarch | 2008-12-08 17:05:43 +0000
Add release date

r26585@agaton (orig r6976):  autarch | 2008-12-08 17:07:40 +0000
 bump version to 0.72
r26605@agaton (orig r6996):  perigrin | 2008-12-09 00:58:39 +0000
add breadcrumbs to describe the Inheritance hierarchy of Class -> Module -> Package -> Object so people can find methods a little easier
r26635@agaton (orig r7026):  shlomif | 2008-12-09 16:48:42 +0000
Fixed some of the tests under perl -d.

    * t/082_get_code_info.t
      - Add $^P &= ~0x200; (per Ovid's suggestion) in order to not munger
        anonymous subs when under -d and so making the tests succeed
        in that case.

23 files changed:
Changes
MANIFEST
MOP.xs
README
lib/Class/MOP.pm
lib/Class/MOP/Attribute.pm
lib/Class/MOP/Class.pm
lib/Class/MOP/Immutable.pm
lib/Class/MOP/Instance.pm
lib/Class/MOP/Method.pm
lib/Class/MOP/Method/Accessor.pm
lib/Class/MOP/Method/Constructor.pm
lib/Class/MOP/Method/Generated.pm
lib/Class/MOP/Method/Wrapped.pm
lib/Class/MOP/Module.pm
lib/Class/MOP/Object.pm
lib/Class/MOP/Package.pm
lib/metaclass.pm
t/080_meta_package.t
t/082_get_code_info.t
t/304_constant_codeinfo.t
t/305_RT_41255.t
typemap [new file with mode: 0644]

diff --git a/Changes b/Changes
index b9fdc95..f1055e7 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,5 +1,30 @@
 Revision history for Perl extension Class-MOP.
 
+    * t/082_get_code_info.t
+      - Add $^P &= ~0x200; (per Ovid's suggestion) in order to not munger
+        anonymous subs when under -d and so making the tests succeed
+        in that case.
+
+0.72 Mon, December 8, 2008
+    * Class::MOP::Package
+      - Pass options to _new, so subclass' attributes can be
+        initialized (Sartak)
+    * Class::MOP::Method
+      - In the docs, indicate that package_name and name are required
+        when calling ->wrap (Stefan O'Rear)
+
+0.71_02 Fri, December 5, 2008
+    * Class::MOP::Immutable
+      - Added a new attribute, inlined_constructor, which is true if
+        the constructor was inlined.
+    * Class::MOP::Package
+      - Make get_all_package_symbols return a hash ref in scalar
+        context and deprecate calling it in list context with a
+        warning. (Florian Ragwitz)
+    * MOP.xs
+      - Various improvements and refactoring, making things more robust and
+        easier to maintain. (Florian Ragwitz)
+
 0.71_01 Wed, December 3, 2008
     * Class::MOP::Method
       - Add an "execute" method to invoke the body so
@@ -20,9 +45,6 @@ Revision history for Perl extension Class-MOP.
       - Make the behaviour of of get_all_package_symbols (and
         therefore get_method_map) consistent for stub methods. Report
         and test by Goro Fuji (rt.cpan.org #41255). (Florian Ragwitz)
-    * Class::MOP::Immutable
-      - Added a new attribute, inlined_constructor, which is true if
-        the constructor was inlined.
 
 0.71 Wed November 26, 2008
     * Class::MOP::Class
index 7cc5cce..c6c39be 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -95,3 +95,4 @@ t/lib/MyMetaClass/Instance.pm
 t/lib/MyMetaClass/Method.pm
 t/lib/MyMetaClass/Random.pm
 t/lib/SyntaxError.pm
+typemap
diff --git a/MOP.xs b/MOP.xs
index 09e90cd..cc82e64 100644 (file)
--- a/MOP.xs
+++ b/MOP.xs
@@ -9,6 +9,7 @@ This shuts up warnings from gcc -Wall
 #include "perl.h"
 #include "XSUB.h"
 
+#define NEED_newRV_noinc
 #define NEED_sv_2pv_flags
 #define NEED_sv_2pv_nolen
 #include "ppport.h"
@@ -25,9 +26,15 @@ U32 hash_package_name;
 SV *key_body;
 U32 hash_body;
 
-SV* method_metaclass;
-SV* associated_metaclass;
-SV* wrap;
+SV *key_package_cache_flag;
+U32 hash_package_cache_flag;
+
+SV *key_methods;
+U32 hash_methods;
+
+SV *method_metaclass;
+SV *associated_metaclass;
+SV *wrap;
 
 
 #define check_package_cache_flag(stash) mop_check_package_cache_flag(aTHX_ stash)
@@ -47,7 +54,7 @@ mop_check_package_cache_flag(pTHX_ HV* stash) {
 #else /* pre 5.10.0 */
 
 static UV
-mop_check_package_cache_flag(pTHX_ HV* stash) {
+mop_check_package_cache_flag(pTHX_ HV *stash) {
     PERL_UNUSED_ARG(stash);
     assert(SvTYPE(stash) == SVt_PVHV);
 
@@ -56,10 +63,10 @@ mop_check_package_cache_flag(pTHX_ HV* stash) {
 #endif
 
 #define call0(s, m)  mop_call0(aTHX_ s, m)
-static SV*
-mop_call0(pTHX_ SV* const self, SV* const method) {
+static SV *
+mop_call0(pTHX_ SV *const self, SV *const method) {
     dSP;
-    SV* ret;
+    SV *ret;
 
     PUSHMARK(SP);
     XPUSHs(self);
@@ -74,100 +81,197 @@ mop_call0(pTHX_ SV* const self, SV* const method) {
     return ret;
 }
 
-static void
-mop_update_method_map(pTHX_ SV* const self, SV* const class_name, HV* const stash, HV* const map) {
-    const char* const class_name_pv = HvNAME(stash); /* must be HvNAME(stash), not SvPV_nolen_const(class_name) */
-    SV*   method_metaclass_name;
-    char* method_name;
-    I32   method_name_len;
-    GV* gv;
-    dSP;
+static int
+get_code_info (SV *coderef, char **pkg, char **name)
+{
+    if (!SvOK(coderef) || !SvROK(coderef) || SvTYPE(SvRV(coderef)) != SVt_PVCV) {
+        return 0;
+    }
 
-    /* this function massivly overlaps with the xs version of
-     * get_all_package_symbols. a common c function to walk the symbol table
-     * should be factored out and used by both.  --rafl */
+    coderef = SvRV(coderef);
+    /* I think this only gets triggered with a mangled coderef, but if
+       we hit it without the guard, we segfault. The slightly odd return
+       value strikes me as an improvement (mst)
+    */
+#ifdef isGV_with_GP
+    if ( isGV_with_GP(CvGV(coderef)) ) {
+#endif
+        *pkg     = HvNAME( GvSTASH(CvGV(coderef)) );
+        *name    = GvNAME( CvGV(coderef) );
+#ifdef isGV_with_GP
+    } else {
+        *pkg     = "__UNKNOWN__";
+        *name    = "__ANON__";
+    }
+#endif
+
+    return 1;
+}
+
+typedef enum {
+    TYPE_FILTER_NONE,
+    TYPE_FILTER_CODE,
+    TYPE_FILTER_ARRAY,
+    TYPE_FILTER_IO,
+    TYPE_FILTER_HASH,
+    TYPE_FILTER_SCALAR,
+} type_filter_t;
+
+static HV *
+get_all_package_symbols(HV *stash, type_filter_t filter)
+{
+    HE *he;
+    HV *ret = newHV();
+
+    (void)hv_iterinit(stash);
+
+    if (filter == TYPE_FILTER_NONE) {
+        while ( (he = hv_iternext(stash)) ) {
+            STRLEN keylen;
+            char *key = HePV(he, keylen);
+            if (!hv_store(ret, key, keylen, SvREFCNT_inc(HeVAL(he)), 0)) {
+                croak("failed to store glob ref");
+            }
+        }
+
+        return ret;
+    }
 
-    hv_iterinit(stash);
-    while ( (gv = (GV*)hv_iternextsv(stash, &method_name, &method_name_len)) ) {
-        CV* cv;
-        switch (SvTYPE (gv)) {
+    while ( (he = hv_iternext(stash)) ) {
+        SV *const gv = HeVAL(he);
+        SV *sv = NULL;
+        char *key;
+        STRLEN keylen;
+        char *package;
+        SV *fq;
+
+        switch( SvTYPE(gv) ) {
 #ifndef SVt_RV
             case SVt_RV:
 #endif
-            case SVt_IV:
             case SVt_PV:
-                /* rafl says that this wastes memory savings that GvSVs have
-                   in 5.8.9 and 5.10.x. But without it some tests fail. rafl
-                   says the right thing to do is to handle GvSVs differently
-                   here. */
-                gv_init((GV*)gv, stash, method_name, method_name_len, GV_ADDMULTI);
+            case SVt_IV:
+                /* expand the gv into a real typeglob if it
+                 * contains stub functions and we were asked to
+                 * return CODE symbols */
+                if (filter == TYPE_FILTER_CODE) {
+                    if (SvROK(gv)) {
+                        /* we don't really care about the length,
+                           but that's the API */
+                        key = HePV(he, keylen);
+                        package = HvNAME(stash);
+                        fq = newSVpvf("%s::%s", package, key);
+                        sv = (SV *)get_cv(SvPV_nolen(fq), 0);
+                        break;
+                    }
+
+                    key = HePV(he, keylen);
+                    gv_init((GV *)gv, stash, key, keylen, GV_ADDMULTI);
+                }
                 /* fall through */
-            default:
+            case SVt_PVGV:
+                switch (filter) {
+                    case TYPE_FILTER_CODE:   sv = (SV *)GvCVu(gv); break;
+                    case TYPE_FILTER_ARRAY:  sv = (SV *)GvAV(gv);  break;
+                    case TYPE_FILTER_IO:     sv = (SV *)GvIO(gv);  break;
+                    case TYPE_FILTER_HASH:   sv = (SV *)GvHV(gv);  break;
+                    case TYPE_FILTER_SCALAR: sv = (SV *)GvSV(gv);  break;
+                    default:
+                        croak("Unknown type");
+                }
                 break;
+            default:
+                continue;
         }
 
-        if ( SvTYPE(gv) == SVt_PVGV && (cv = GvCVu(gv)) ) {
-            GV* const cvgv = CvGV(cv);
-            /* ($cvpkg_name, $cv_name) = get_code_info($cv) */
-            const char* const cvpkg_name = HvNAME(GvSTASH(cvgv));
-            const char* const cv_name    = GvNAME(cvgv);
-            SV* method_slot;
-            SV* method_object;
-
-            /* this checks to see that the subroutine is actually from our package  */
-            if ( !(strEQ(cvpkg_name, "constant") && strEQ(cv_name, "__ANON__")) ) {
-                if ( strNE(cvpkg_name, class_name_pv) ) {
-                    continue;
-                }
+        if (sv) {
+            char *key = HePV(he, keylen);
+            if (!hv_store(ret, key, keylen, newRV_inc(sv), 0)) {
+                croak("failed to store symbol ref");
             }
+        }
+    }
 
-            method_slot = *hv_fetch(map, method_name, method_name_len, TRUE);
-            if ( SvOK(method_slot) ) {
-                SV* const body = call0(method_slot, key_body); /* $method_object->body() */
-                if ( SvROK(body) && ((CV*) SvRV(body)) == cv ) {
-                    continue;
-                }
+    return ret;
+}
+
+
+static void
+mop_update_method_map(pTHX_ SV *const self, SV *const class_name, HV *const stash, HV *const map) {
+    const char *const class_name_pv = HvNAME(stash); /* must be HvNAME(stash), not SvPV_nolen_const(class_name) */
+    SV   *method_metaclass_name;
+    char *method_name;
+    I32   method_name_len;
+    SV   *coderef;
+    HV   *symbols;
+    dSP;
+
+    symbols = get_all_package_symbols(stash, TYPE_FILTER_CODE);
+
+    (void)hv_iterinit(symbols);
+    while ( (coderef = hv_iternextsv(symbols, &method_name, &method_name_len)) ) {
+        CV *cv = (CV *)SvRV(coderef);
+        char *cvpkg_name;
+        char *cv_name;
+        SV *method_slot;
+        SV *method_object;
+
+        if (!get_code_info(coderef, &cvpkg_name, &cv_name)) {
+            continue;
+        }
+
+        /* this checks to see that the subroutine is actually from our package  */
+        if ( !(strEQ(cvpkg_name, "constant") && strEQ(cv_name, "__ANON__")) ) {
+            if ( strNE(cvpkg_name, class_name_pv) ) {
+                continue;
             }
+        }
 
-            method_metaclass_name = call0(self, method_metaclass); /* $self->method_metaclass() */
-
-            /*
-                $method_object = $method_metaclass->wrap(
-                    $cv,
-                    associated_metaclass => $self,
-                    package_name         => $class_name,
-                    name                 => $method_name
-                );
-            */
-            ENTER;
-            SAVETMPS;
-
-            PUSHMARK(SP);
-            EXTEND(SP, 8);
-            PUSHs(method_metaclass_name); /* invocant */
-            mPUSHs(newRV_inc((SV*)cv));
-            PUSHs(associated_metaclass);
-            PUSHs(self);
-            PUSHs(key_package_name);
-            PUSHs(class_name);
-            PUSHs(key_name);
-            mPUSHs(newSVpv(method_name, method_name_len));
-            PUTBACK;
-
-            call_sv(wrap, G_SCALAR | G_METHOD);
-            SPAGAIN;
-            method_object = POPs;
-            PUTBACK;
-            /* $map->{$method_name} = $method_object */
-            sv_setsv(method_slot, method_object);
-
-            FREETMPS;
-            LEAVE;
+        method_slot = *hv_fetch(map, method_name, method_name_len, TRUE);
+        if ( SvOK(method_slot) ) {
+            SV *const body = call0(method_slot, key_body); /* $method_object->body() */
+            if ( SvROK(body) && ((CV *) SvRV(body)) == cv ) {
+                continue;
+            }
         }
+
+        method_metaclass_name = call0(self, method_metaclass); /* $self->method_metaclass() */
+
+        /*
+            $method_object = $method_metaclass->wrap(
+                $cv,
+                associated_metaclass => $self,
+                package_name         => $class_name,
+                name                 => $method_name
+            );
+        */
+        ENTER;
+        SAVETMPS;
+
+        PUSHMARK(SP);
+        EXTEND(SP, 8);
+        PUSHs(method_metaclass_name); /* invocant */
+        mPUSHs(newRV_inc((SV *)cv));
+        PUSHs(associated_metaclass);
+        PUSHs(self);
+        PUSHs(key_package_name);
+        PUSHs(class_name);
+        PUSHs(key_name);
+        mPUSHs(newSVpv(method_name, method_name_len));
+        PUTBACK;
+
+        call_sv(wrap, G_SCALAR | G_METHOD);
+        SPAGAIN;
+        method_object = POPs;
+        PUTBACK;
+        /* $map->{$method_name} = $method_object */
+        sv_setsv(method_slot, method_object);
+
+        FREETMPS;
+        LEAVE;
     }
 }
 
-
 /*
 get_code_info:
   Pass in a coderef, returns:
@@ -182,11 +286,15 @@ BOOT:
     key_body = newSVpvs("body");
     key_package = newSVpvs("package");
     key_package_name = newSVpvs("package_name");
+    key_package_cache_flag = newSVpvs("_package_cache_flag");
+    key_methods = newSVpvs("methods");
 
     PERL_HASH(hash_name, "name", 4);
     PERL_HASH(hash_body, "body", 4);
     PERL_HASH(hash_package, "package", 7);
     PERL_HASH(hash_package_name, "package_name", 12);
+    PERL_HASH(hash_package_cache_flag, "_package_cache_flag", 19);
+    PERL_HASH(hash_methods, "methods", 7);
 
     method_metaclass     = newSVpvs("method_metaclass");
     wrap                 = newSVpvs("wrap");
@@ -198,140 +306,76 @@ PROTOTYPES: ENABLE
 
 void
 get_code_info(coderef)
-  SV* coderef
-  PREINIT:
-    char* name;
-    char* pkg;
-  PPCODE:
-    if ( SvOK(coderef) && SvROK(coderef) && SvTYPE(SvRV(coderef)) == SVt_PVCV ) {
-      coderef = SvRV(coderef);
-      /* I think this only gets triggered with a mangled coderef, but if
-         we hit it without the guard, we segfault. The slightly odd return
-         value strikes me as an improvement (mst)
-      */
-#ifdef isGV_with_GP
-      if ( isGV_with_GP(CvGV(coderef)) ) {
-#endif
-        pkg     = HvNAME( GvSTASH(CvGV(coderef)) );
-        name    = GvNAME( CvGV(coderef) );
-#ifdef isGV_with_GP
-      } else {
-        pkg     = "__UNKNOWN__";
-        name    = "__ANON__";
-      }
-#endif
-
-      EXTEND(SP, 2);
-      PUSHs(newSVpvn(pkg, strlen(pkg)));
-      PUSHs(newSVpvn(name, strlen(name)));
-    }
+    SV *coderef
+    PREINIT:
+        char *pkg  = NULL;
+        char *name = NULL;
+    PPCODE:
+        if (get_code_info(coderef, &pkg, &name)) {
+            EXTEND(SP, 2);
+            PUSHs(newSVpv(pkg, 0));
+            PUSHs(newSVpv(name, 0));
+        }
 
 
 MODULE = Class::MOP   PACKAGE = Class::MOP::Package
 
 void
-get_all_package_symbols(self, ...)
+get_all_package_symbols(self, filter=TYPE_FILTER_NONE)
     SV *self
+    type_filter_t filter
     PROTOTYPE: $;$
     PREINIT:
         HV *stash = NULL;
-        SV *type_filter = NULL;
+        HV *symbols = NULL;
         register HE *he;
     PPCODE:
         if ( ! SvROK(self) ) {
             die("Cannot call get_all_package_symbols as a class method");
         }
 
-        switch (GIMME_V) {
-            case G_VOID: return; break;
-            case G_SCALAR: ST(0) = &PL_sv_undef; return; break;
+        if (GIMME_V == G_VOID) {
+            XSRETURN_EMPTY;
         }
 
-        if ( items > 1 ) type_filter = ST(1);
 
         PUTBACK;
 
-        if ( (he = hv_fetch_ent((HV *)SvRV(self), key_package, 0, hash_package)) )
-            stash = gv_stashsv(HeVAL(he),0);
+        if ( (he = hv_fetch_ent((HV *)SvRV(self), key_package, 0, hash_package)) ) {
+            stash = gv_stashsv(HeVAL(he), 0);
+        }
 
-        if (stash) {
 
-            (void)hv_iterinit(stash);
+        if (!stash) {
+            switch (GIMME_V) {
+                case G_SCALAR: XSRETURN_UNDEF; break;
+                case G_ARRAY:  XSRETURN_EMPTY; break;
+            }
+        }
 
-            if ( type_filter && SvPOK(type_filter) ) {
-                const char *const type = SvPV_nolen(type_filter);
+        symbols = get_all_package_symbols(stash, filter);
 
-                while ( (he = hv_iternext(stash)) ) {
-                    SV *const gv = HeVAL(he);
-                    SV *sv = NULL;
-                    char *key;
-                    STRLEN keylen;
-                    char *package;
-                    SV *fq;
+        switch (GIMME_V) {
+            case G_SCALAR:
+                PUSHs(sv_2mortal(newRV_inc((SV *)symbols)));
+                break;
+            case G_ARRAY:
+                warn("Class::MOP::Package::get_all_package_symbols in list context is deprecated. use scalar context instead.");
 
-                    switch( SvTYPE(gv) ) {
-#ifndef SVt_RV
-                        case SVt_RV:
-#endif
-                        case SVt_PV:
-                        case SVt_IV:
-                            /* expand the gv into a real typeglob if it
-                             * contains stub functions and we were asked to
-                             * return CODE symbols */
-                            if (*type == 'C') {
-                                if (SvROK(gv)) {
-                                    /* we don't really care about the length,
-                                       but that's the API */
-                                    key = HePV(he, keylen);
-                                    package = HvNAME(stash);
-                                    fq = newSVpvf("%s::%s", package, key);
-                                    sv = (SV*)get_cv(SvPV_nolen(fq), 0);
-                                    break;
-                                }
-
-                                key = HePV(he, keylen);
-                                gv_init((GV *)gv, stash, key, keylen, GV_ADDMULTI);
-                            }
-                            /* fall through */
-                        case SVt_PVGV:
-                            switch (*type) {
-                                case 'C': sv = (SV *)GvCVu(gv); break; /* CODE */
-                                case 'A': sv = (SV *)GvAV(gv); break; /* ARRAY */
-                                case 'I': sv = (SV *)GvIO(gv); break; /* IO */
-                                case 'H': sv = (SV *)GvHV(gv); break; /* HASH */
-                                case 'S': sv = (SV *)GvSV(gv); break; /* SCALAR */
-                                default:
-                                          croak("Unknown type %s\n", type);
-                            }
-                            break;
-                        default:
-                            continue;
-                    }
+                EXTEND(SP, HvKEYS(symbols) * 2);
 
-                    if (sv) {
-                        SV *key = hv_iterkeysv(he);
-                        SPAGAIN;
-                        EXTEND(SP, 2);
-                        PUSHs(key);
-                        PUSHs(sv_2mortal(newRV_inc(sv)));
-                        PUTBACK;
-                    }
+                while ((he = hv_iternext(symbols))) {
+                    PUSHs(hv_iterkeysv(he));
+                    PUSHs(sv_2mortal(SvREFCNT_inc(HeVAL(he))));
                 }
-            } else {
-                EXTEND(SP, HvKEYS(stash) * 2);
-
-                while ( (he = hv_iternext(stash)) ) {
-                    SV *key = hv_iterkeysv(he);
-                    SV *sv = HeVAL(he);
-                    SPAGAIN;
-                    PUSHs(key);
-                    PUSHs(sv);
-                    PUTBACK;
-                }
-            }
 
+                break;
+            default:
+                break;
         }
 
+        SvREFCNT_dec((SV *)symbols);
+
 void
 name(self)
     SV *self
@@ -416,35 +460,25 @@ MODULE = Class::MOP    PACKAGE = Class::MOP::Class
 
 void
 get_method_map(self)
-    SV* self
+    SV *self
     PREINIT:
-        SV* const class_name = HeVAL( hv_fetch_ent((HV*)SvRV(self), key_package, TRUE, hash_package) );
-        HV* const stash      = gv_stashsv(class_name, TRUE);
+        HV *const obj        = (HV *)SvRV(self);
+        SV *const class_name = HeVAL( hv_fetch_ent(obj, key_package, 0, hash_package) );
+        HV *const stash      = gv_stashsv(class_name, 0);
         UV  const current    = check_package_cache_flag(stash);
-        SV* const cache_flag = *hv_fetchs((HV*)SvRV(self), "_package_cache_flag", TRUE);
-        SV* const map_ref    = *hv_fetchs((HV*)SvRV(self), "methods", TRUE);
+        SV *const cache_flag = HeVAL( hv_fetch_ent(obj, key_package_cache_flag, TRUE, hash_package_cache_flag));
+        SV *const map_ref    = HeVAL( hv_fetch_ent(obj, key_methods, TRUE, hash_methods));
     PPCODE:
-        if ( ! SvRV(self) ) {
-            die("Cannot call get_method_map as a class method");
-        }
-
         /* in  $self->{methods} does not yet exist (or got deleted) */
-        if ( ! (SvROK(map_ref) && SvTYPE(SvRV(map_ref)) == SVt_PVHV) ) {
-            SV* new_map_ref = newRV_noinc((SV*)newHV());
+        if ( !SvROK(map_ref) || SvTYPE(SvRV(map_ref)) != SVt_PVHV ) {
+            SV *new_map_ref = newRV_noinc((SV *)newHV());
             sv_2mortal(new_map_ref);
             sv_setsv(map_ref, new_map_ref);
         }
 
-        if ( ! (SvOK(cache_flag) && SvUV(cache_flag) == current) ) {
-            ENTER;
-            SAVETMPS;
-
-            mop_update_method_map(aTHX_ self, class_name, stash, (HV*)SvRV(map_ref));
+        if ( !SvOK(cache_flag) || SvUV(cache_flag) != current ) {
+            mop_update_method_map(aTHX_ self, class_name, stash, (HV *)SvRV(map_ref));
             sv_setuv(cache_flag, check_package_cache_flag(stash)); /* update_cache_flag() */
-
-            FREETMPS;
-            LEAVE;
         }
 
         XPUSHs(map_ref);
-
diff --git a/README b/README
index 688e34f..ac36d67 100644 (file)
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-Class::MOP version 0.71_01
+Class::MOP version 0.72
 ===========================
 
 See the individual module documentation for more information
index 712bc6c..efb038b 100644 (file)
@@ -31,7 +31,7 @@ BEGIN {
     *check_package_cache_flag = \&mro::get_pkg_gen;
 }
 
-our $VERSION   = '0.71_01';
+our $VERSION   = '0.72';
 our $XS_VERSION = $VERSION;
 $VERSION = eval $VERSION;
 our $AUTHORITY = 'cpan:STEVAN';    
index 91d583a..97b7d78 100644 (file)
@@ -9,7 +9,7 @@ use Class::MOP::Method::Accessor;
 use Carp         'confess';
 use Scalar::Util 'blessed', 'weaken';
 
-our $VERSION   = '0.71_01';
+our $VERSION   = '0.72';
 $VERSION = eval $VERSION;
 our $AUTHORITY = 'cpan:STEVAN';
 
index bc392a6..65ae31a 100644 (file)
@@ -11,7 +11,7 @@ use Class::MOP::Method::Wrapped;
 use Carp         'confess';
 use Scalar::Util 'blessed', 'weaken';
 
-our $VERSION   = '0.71_01';
+our $VERSION   = '0.72';
 $VERSION = eval $VERSION;
 our $AUTHORITY = 'cpan:STEVAN';
 
@@ -311,8 +311,6 @@ sub attribute_metaclass { $_[0]->{'attribute_metaclass'} }
 sub method_metaclass    { $_[0]->{'method_metaclass'}    }
 sub instance_metaclass  { $_[0]->{'instance_metaclass'}  }
 
-# FIXME:
-# this is a prime canidate for conversion to XS
 sub get_method_map {
     my $self = shift;
 
@@ -330,10 +328,10 @@ sub get_method_map {
 
     my $method_metaclass = $self->method_metaclass;
 
-    my %all_code = $self->get_all_package_symbols('CODE');
+    my $all_code = $self->get_all_package_symbols('CODE');
 
-    foreach my $symbol (keys %all_code) {
-        my $code = $all_code{$symbol};
+    foreach my $symbol (keys %{ $all_code }) {
+        my $code = $all_code->{$symbol};
 
         next if exists  $map->{$symbol} &&
                 defined $map->{$symbol} &&
@@ -1185,6 +1183,10 @@ manipulation of Perl 5 classes (and it can create them too). The
 best way to understand what this module can do, is to read the
 documentation for each of it's methods.
 
+=head1 INHERITANCE
+
+B<Class::MOP::Class> is a subclass of L<Class::MOP::Module>
+
 =head1 METHODS
 
 =head2 Self Introspection
index 851cdaf..4357438 100644 (file)
@@ -9,7 +9,7 @@ use Class::MOP::Method::Constructor;
 use Carp         'confess';
 use Scalar::Util 'blessed';
 
-our $VERSION   = '0.71_01';
+our $VERSION   = '0.72';
 $VERSION = eval $VERSION;
 our $AUTHORITY = 'cpan:STEVAN';
 
index 3a34042..65e3dc4 100644 (file)
@@ -6,7 +6,7 @@ use warnings;
 
 use Scalar::Util 'weaken', 'blessed';
 
-our $VERSION   = '0.71_01';
+our $VERSION   = '0.72';
 $VERSION = eval $VERSION;
 our $AUTHORITY = 'cpan:STEVAN';
 
index ab1f004..77f52ff 100644 (file)
@@ -7,7 +7,7 @@ use warnings;
 use Carp         'confess';
 use Scalar::Util 'weaken';
 
-our $VERSION   = '0.71_01';
+our $VERSION   = '0.72';
 $VERSION = eval $VERSION;
 our $AUTHORITY = 'cpan:STEVAN';
 
@@ -168,10 +168,8 @@ to this class.
 =item B<wrap ($code, %params)>
 
 This is the basic constructor, it returns a B<Class::MOP::Method>
-instance which wraps the given C<$code> reference. You can also
-set the C<package_name> and C<name> attributes using the C<%params>.
-If these are not set, then thier accessors will attempt to figure
-it out using the C<Class::MOP::get_code_info> function.
+instance which wraps the given C<$code> reference. You must also set
+the C<package_name> and C<name> attributes in C<%params>.
 
 =item B<clone (%params)>
 
index 8e52f22..6017a43 100644 (file)
@@ -7,7 +7,7 @@ use warnings;
 use Carp         'confess';
 use Scalar::Util 'blessed', 'weaken';
 
-our $VERSION   = '0.71_01';
+our $VERSION   = '0.72';
 $VERSION = eval $VERSION;
 our $AUTHORITY = 'cpan:STEVAN';
 
index aeaa607..e19839a 100644 (file)
@@ -7,7 +7,7 @@ use warnings;
 use Carp         'confess';
 use Scalar::Util 'blessed', 'weaken', 'looks_like_number';
 
-our $VERSION   = '0.71_01';
+our $VERSION   = '0.72';
 $VERSION = eval $VERSION;
 our $AUTHORITY = 'cpan:STEVAN';
 
index 428d808..1cbdadc 100644 (file)
@@ -6,7 +6,7 @@ use warnings;
 
 use Carp 'confess';
 
-our $VERSION   = '0.71_01';
+our $VERSION   = '0.72';
 $VERSION = eval $VERSION;
 our $AUTHORITY = 'cpan:STEVAN';
 
index b2c4e15..9342006 100644 (file)
@@ -7,7 +7,7 @@ use warnings;
 use Carp         'confess';
 use Scalar::Util 'blessed';
 
-our $VERSION   = '0.71_01';
+our $VERSION   = '0.72';
 $VERSION = eval $VERSION;
 our $AUTHORITY = 'cpan:STEVAN';
 
index 03d4c30..afaacc1 100644 (file)
@@ -7,7 +7,7 @@ use warnings;
 use Carp         'confess';
 use Scalar::Util 'blessed';
 
-our $VERSION   = '0.71_01';
+our $VERSION   = '0.72';
 $VERSION = eval $VERSION;
 our $AUTHORITY = 'cpan:STEVAN';
 
@@ -68,6 +68,10 @@ This is an abstraction of a Perl 5 module, it is a superclass of
 L<Class::MOP::Class>. A module essentially a package with metadata, 
 in our case the version and authority. 
 
+=head1 INHERITANCE
+
+B<Class::MOP::Module> is a subclass of L<Class::MOP::Package>
+
 =head1 METHODS
 
 =over 4
index b4b9dbc..4ce9c56 100644 (file)
@@ -6,7 +6,7 @@ use warnings;
 
 use Scalar::Util 'blessed';
 
-our $VERSION   = '0.71_01';
+our $VERSION   = '0.72';
 $VERSION = eval $VERSION;
 our $AUTHORITY = 'cpan:STEVAN';
 
@@ -49,7 +49,7 @@ Class::MOP::Object - Object Meta Object
 
 =head1 DESCRIPTION
 
-This class is basically a stub, it provides no functionality at all, 
+This class is basically a stub, it provides almost no functionality at all, 
 and really just exists to make the Class::MOP metamodel complete.
 
                          ......
index 96ad798..0b7e5c4 100644 (file)
@@ -8,7 +8,7 @@ use B;
 use Scalar::Util 'blessed';
 use Carp         'confess';
 
-our $VERSION   = '0.71_01';
+our $VERSION   = '0.72';
 $VERSION = eval $VERSION;
 our $AUTHORITY = 'cpan:STEVAN';
 
@@ -32,6 +32,7 @@ sub initialize {
     } else {
         my $meta = ( ref $class || $class )->_new({
             'package'   => $package_name,
+            %options,
         });
 
         Class::MOP::store_metaclass_by_name($package_name, $meta);
@@ -283,13 +284,18 @@ sub get_all_package_symbols {
 
     my $namespace = $self->namespace;
 
-    return %$namespace unless defined $type_filter;
+    if (wantarray) {
+        warn 'Class::MOP::Package::get_all_package_symbols in list context is deprecated. use scalar context instead.';
+    }
+
+    return (wantarray ? %$namespace : $namespace) unless defined $type_filter;
 
+    my %ret;
     # for some reason this nasty impl is orders of magnitude faster than a clean version
     if ( $type_filter eq 'CODE' ) {
         my $pkg;
         no strict 'refs';
-        return map {
+        %ret = map {
             (ref($namespace->{$_})
                 ? ( $_ => \&{$pkg ||= $self->name . "::$_"} )
                 : ( ref \$namespace->{$_} eq 'GLOB' # don't use {CODE} unless it's really a glob to prevent stringification of stubs
@@ -303,12 +309,14 @@ sub get_all_package_symbols {
                             : () }) ) )
         } keys %$namespace;
     } else {
-        return map {
+        %ret = map {
             $_ => *{$namespace->{$_}}{$type_filter}
         } grep {
             !ref($namespace->{$_}) && *{$namespace->{$_}}{$type_filter}
         } keys %$namespace;
     }
+
+    return wantarray ? %ret : \%ret;
 }
 
 1;
@@ -327,6 +335,10 @@ This is an abstraction of a Perl 5 package, it is a superclass of
 L<Class::MOP::Class> and provides all of the symbol table 
 introspection methods.
 
+=head1 INHERITANCE
+
+B<Class::MOP::Package> is a subclass of L<Class::MOP::Object>
+
 =head1 METHODS
 
 =over 4
index 0db358a..4f71b22 100644 (file)
@@ -7,7 +7,7 @@ use warnings;
 use Carp         'confess';
 use Scalar::Util 'blessed';
 
-our $VERSION   = '0.71_01';
+our $VERSION   = '0.72';
 $VERSION = eval $VERSION;
 our $AUTHORITY = 'cpan:STEVAN';
 
index 4a8b03e..4ef0554 100644 (file)
@@ -234,46 +234,46 @@ is(Foo->meta->get_package_symbol('@foo'), $ARRAY, '... got the right values for
 # get_all_package_symbols
 
 {
-    my %syms = Foo->meta->get_all_package_symbols;
+    my $syms = Foo->meta->get_all_package_symbols;
     is_deeply(
-        [ sort keys %syms ],
+        [ sort keys %{ $syms } ],
         [ sort Foo->meta->list_all_package_symbols ],
         '... the fetched symbols are the same as the listed ones'
     ); 
 }
 
 {
-    my %syms = Foo->meta->get_all_package_symbols('CODE');
+    my $syms = Foo->meta->get_all_package_symbols('CODE');
 
     is_deeply(
-        [ sort keys %syms ],
+        [ sort keys %{ $syms } ],
         [ sort Foo->meta->list_all_package_symbols('CODE') ],
         '... the fetched symbols are the same as the listed ones'
     );
     
-    foreach my $symbol (keys %syms) {
-        is($syms{$symbol}, Foo->meta->get_package_symbol('&' . $symbol), '... got the right symbol');
+    foreach my $symbol (keys %{ $syms }) {
+        is($syms->{$symbol}, Foo->meta->get_package_symbol('&' . $symbol), '... got the right symbol');
     } 
 }
 
 {
     Foo->meta->add_package_symbol('%zork');
 
-    my %syms = Foo->meta->get_all_package_symbols('HASH');
+    my $syms = Foo->meta->get_all_package_symbols('HASH');
 
     is_deeply(
-        [ sort keys %syms ],
+        [ sort keys %{ $syms } ],
         [ sort Foo->meta->list_all_package_symbols('HASH') ],
         '... the fetched symbols are the same as the listed ones'
     );
 
-    foreach my $symbol (keys %syms) {
-        is($syms{$symbol}, Foo->meta->get_package_symbol('%' . $symbol), '... got the right symbol');
+    foreach my $symbol (keys %{ $syms }) {
+        is($syms->{$symbol}, Foo->meta->get_package_symbol('%' . $symbol), '... got the right symbol');
     }
 
     no warnings 'once';
     is_deeply(
-        \%syms,
+        $syms,
         { zork => \%Foo::zork },
         "got the right ones",
     );
index e3c74e0..700d36d 100644 (file)
@@ -6,6 +6,7 @@ use warnings;
 use Test::More;
 
 BEGIN {
+    $^P &= ~0x200; # Don't munger anonymous sub names
     if ( eval 'use Sub::Name qw(subname); 1;' ) {
         plan tests => 5;
     }
index eae71e5..463b4ca 100644 (file)
@@ -13,10 +13,10 @@ use Class::MOP;
 
 my $meta = Class::MOP::Class->initialize('Foo');
 
-my %syms = $meta->get_all_package_symbols('CODE');
-is(ref $syms{FOO}, 'CODE', 'get constant symbol');
+my $syms = $meta->get_all_package_symbols('CODE');
+is(ref $syms->{FOO}, 'CODE', 'get constant symbol');
 
-undef %syms;
+undef $syms;
 
-%syms = $meta->get_all_package_symbols('CODE');
-is(ref $syms{FOO}, 'CODE', 'constant symbol still there, although we dropped our reference');
+$syms = $meta->get_all_package_symbols('CODE');
+is(ref $syms->{FOO}, 'CODE', 'constant symbol still there, although we dropped our reference');
index 676a27d..3431127 100644 (file)
@@ -7,7 +7,7 @@ use Test::Exception;
 use Class::MOP;
 
 {
-    package Base;
+    package BaseClass;
     sub m1 { 1 }
     sub m2 { 2 }
     sub m3 { 3 }
@@ -15,7 +15,7 @@ use Class::MOP;
     sub m5 { 5 }
 
     package Derived;
-    use base qw(Base);
+    use base qw(BaseClass);
 
     sub m1;
     sub m2 ();
diff --git a/typemap b/typemap
new file mode 100644 (file)
index 0000000..7ab39e1
--- /dev/null
+++ b/typemap
@@ -0,0 +1,17 @@
+type_filter_t  T_TYPE_FILTER
+
+INPUT
+
+T_TYPE_FILTER
+    {
+        const char *__tMp = SvPV_nolen($arg);
+        switch (*__tMp) {
+            case 'C': $var = TYPE_FILTER_CODE;   break;
+            case 'A': $var = TYPE_FILTER_ARRAY;  break;
+            case 'I': $var = TYPE_FILTER_IO;     break;
+            case 'H': $var = TYPE_FILTER_HASH;   break;
+            case 'S': $var = TYPE_FILTER_SCALAR; break;
+            default:
+                croak(\"Unknown type %s\\n\", __tMp);
+        }
+    }