Allow requiring a version with is_class_loaded, load_class and load_first_existing_class.
[gitmo/Class-MOP.git] / xs / MOP.xs
index 959df7a..fd4bf1d 100644 (file)
--- a/xs/MOP.xs
+++ b/xs/MOP.xs
@@ -1,9 +1,5 @@
 #include "mop.h"
 
-SV *mop_method_metaclass;
-SV *mop_associated_metaclass;
-SV *mop_wrap;
-
 static bool
 find_method (const char *key, STRLEN keylen, SV *val, void *ud)
 {
@@ -15,8 +11,38 @@ find_method (const char *key, STRLEN keylen, SV *val, void *ud)
     return FALSE;
 }
 
+static bool
+check_version (SV *klass, SV *required_version)
+{
+    bool ret = 0;
+
+    dSP;
+    ENTER;
+    SAVETMPS;
+    PUSHMARK(SP);
+    EXTEND(SP, 2);
+    PUSHs(klass);
+    PUSHs(required_version);
+    PUTBACK;
+
+    call_method("VERSION", G_DISCARD|G_VOID|G_EVAL);
+
+    SPAGAIN;
+
+    if (!SvTRUE(ERRSV)) {
+        ret = 1;
+    }
+
+    PUTBACK;
+    FREETMPS;
+    LEAVE;
+
+    return ret;
+}
+
+EXTERN_C XS(boot_Class__MOP__Mixin__HasMethods);
 EXTERN_C XS(boot_Class__MOP__Package);
-EXTERN_C XS(boot_Class__MOP__Attribute);
+EXTERN_C XS(boot_Class__MOP__Mixin__AttributeCore);
 EXTERN_C XS(boot_Class__MOP__Method);
 
 MODULE = Class::MOP   PACKAGE = Class::MOP
@@ -26,12 +52,9 @@ PROTOTYPES: DISABLE
 BOOT:
     mop_prehash_keys();
 
-    mop_method_metaclass     = newSVpvs("method_metaclass");
-    mop_wrap                 = newSVpvs("wrap");
-    mop_associated_metaclass = newSVpvs("associated_metaclass");
-
+    MOP_CALL_BOOT (boot_Class__MOP__Mixin__HasMethods);
     MOP_CALL_BOOT (boot_Class__MOP__Package);
-    MOP_CALL_BOOT (boot_Class__MOP__Attribute);
+    MOP_CALL_BOOT (boot_Class__MOP__Mixin__AttributeCore);
     MOP_CALL_BOOT (boot_Class__MOP__Method);
 
 # use prototype here to be compatible with get_code_info from Sub::Identify
@@ -50,12 +73,10 @@ get_code_info(coderef)
             mPUSHs(newSVpv(name, 0));
         }
 
-# This is some pretty grotty logic. It _should_ be parallel to the
-# pure Perl version in lib/Class/MOP.pm, so if you want to understand
-# it we suggest you start there.
 void
-is_class_loaded(klass=&PL_sv_undef)
+is_class_loaded(klass, options=NULL)
     SV *klass
+    HV *options
     PREINIT:
         HV *stash;
         bool found_method = FALSE;
@@ -70,6 +91,15 @@ is_class_loaded(klass=&PL_sv_undef)
             XSRETURN_NO;
         }
 
+        if (options && hv_exists_ent(options, KEY_FOR(_version), HASH_FOR(_version))) {
+            HE *required_version = hv_fetch_ent(options, KEY_FOR(_version), 0, HASH_FOR(_version));
+            if (check_version (klass, HeVAL(required_version))) {
+                XSRETURN_YES;
+            }
+
+            XSRETURN_NO;
+        }
+
         if (hv_exists_ent (stash, KEY_FOR(VERSION), HASH_FOR(VERSION))) {
             HE *version = hv_fetch_ent(stash, KEY_FOR(VERSION), 0, HASH_FOR(VERSION));
             SV *version_sv;