With pluggable regexp engines checking "ref" of a qr// isn't correct;
it's also possible for a normal Regex to be blessed into another
class.

Additionally an 'Object' subtype previously excluded objects that were
->isa('Regexp'), this was inconsistent with the RegexpRef handling
(i.e. neither RegexpRef nor isa => 'Regexp' would accept a subclass of
Regexp). The 'Object' subtype now simply checks if the reference is
blessed with no special logic.
---
 Moose.xs                                           |   30 ++++++++++++++++++++
 lib/Moose/Util/TypeConstraints.pm                  |    6 +--
 .../Util/TypeConstraints/OptimizedConstraints.pm   |    4 +-
 .../003_util_std_type_constraints.t                |    3 +-
 4 files changed, 36 insertions(+), 7 deletions(-)

diff --git a/Moose.xs b/Moose.xs
index 874e9e0..fbab473 100644
--- a/Moose.xs
+++ b/Moose.xs
@@ -85,6 +85,26 @@ unset_export_flag (pTHX_ SV *sv, MAGIC *mymg)
     return 0;
 }
 
+#ifndef SvRXOK
+// SvRXOK appeared before Svt_REGEXP did, so this implementation assumes magic
+// based qr//.
+#define SvRXOK(sv) is_regexp(aTHX_ sv)
+
+STATIC int
+is_regexp (pTHX_ SV* sv) {
+    SV* tmpsv;
+
+    if (SvMAGICAL(sv))
+        mg_get(sv);
+    if (SvROK(sv) &&
+      (tmpsv = (SV*) SvRV(sv)) &&
+      SvTYPE(tmpsv) == SVt_PVMG &&
+      (mg_find(tmpsv, PERL_MAGIC_qr)))
+        return TRUE;
+    return FALSE;
+}
+#endif
+
 MODULE = Moose  PACKAGE = Moose::Exporter
 
 void
@@ -100,3 +120,13 @@ _export_is_flagged (SV *sv)
         RETVAL = export_flag_is_set(aTHX_ sv);
     OUTPUT:
         RETVAL
+
+MODULE = Moose PACKAGE = Moose::Util
+
+SV*
+_is_regexp (SV *sv)
+    PROTOTYPE: $
+    CODE:
+        RETVAL = SvRXOK(sv) ? &PL_sv_yes : &PL_sv_no;
+    OUTPUT:
+        RETVAL
diff --git a/lib/Moose/Util/TypeConstraints.pm 
b/lib/Moose/Util/TypeConstraints.pm
index 1f66409..bf3fc5c 100644
--- a/lib/Moose/Util/TypeConstraints.pm
+++ b/lib/Moose/Util/TypeConstraints.pm
@@ -731,7 +731,7 @@ subtype 'Int' => as 'Num' => where { "$_" =~ /^-?[0-9]+$/ } 
=>
 
 subtype 'CodeRef' => as 'Ref' => where { ref($_) eq 'CODE' } =>
     optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::CodeRef;
-subtype 'RegexpRef' => as 'Ref' => where { ref($_) eq 'Regexp' } =>
+subtype 'RegexpRef' => as 'Ref' => where { Moose::Util::_is_regexp($_) } =>
     optimize_as
     \&Moose::Util::TypeConstraints::OptimizedConstraints::RegexpRef;
 subtype 'GlobRef' => as 'Ref' => where { ref($_) eq 'GLOB' } =>
@@ -745,10 +745,8 @@ subtype 'FileHandle' => as 'GlobRef' => where {
 } => optimize_as
     \&Moose::Util::TypeConstraints::OptimizedConstraints::FileHandle;
 
-# NOTE:
-# blessed(qr/.../) returns true,.. how odd
 subtype 'Object' => as 'Ref' =>
-    where { blessed($_) && blessed($_) ne 'Regexp' } =>
+    where { blessed($_) } =>
     optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Object;
 
 # This type is deprecated.
diff --git a/lib/Moose/Util/TypeConstraints/OptimizedConstraints.pm 
b/lib/Moose/Util/TypeConstraints/OptimizedConstraints.pm
index 5d54359..4de2eca 100644
--- a/lib/Moose/Util/TypeConstraints/OptimizedConstraints.pm
+++ b/lib/Moose/Util/TypeConstraints/OptimizedConstraints.pm
@@ -36,12 +36,12 @@ sub ScalarRef { ref($_[0]) eq 'SCALAR' || ref($_[0]) eq 
'REF' }
 sub ArrayRef  { ref($_[0]) eq 'ARRAY'  }
 sub HashRef   { ref($_[0]) eq 'HASH'   }
 sub CodeRef   { ref($_[0]) eq 'CODE'   }
-sub RegexpRef { ref($_[0]) eq 'Regexp' }
+sub RegexpRef { Moose::Util::_is_regexp($_[0]) }
 sub GlobRef   { ref($_[0]) eq 'GLOB'   }
 
 sub FileHandle { ref($_[0]) eq 'GLOB' && Scalar::Util::openhandle($_[0]) or 
blessed($_[0]) && $_[0]->isa("IO::Handle") }
 
-sub Object { blessed($_[0]) && blessed($_[0]) ne 'Regexp' }
+sub Object { blessed($_[0]) }
 
 sub Role {
     Moose::Deprecated::deprecated(
diff --git a/t/040_type_constraints/003_util_std_type_constraints.t 
b/t/040_type_constraints/003_util_std_type_constraints.t
index 20c0f54..75a818c 100644
--- a/t/040_type_constraints/003_util_std_type_constraints.t
+++ b/t/040_type_constraints/003_util_std_type_constraints.t
@@ -256,6 +256,7 @@ ok(!defined RegexpRef($GLOB_REF),        '... RegexpRef 
rejects anything which i
 ok(!defined RegexpRef($fh),              '... RegexpRef rejects anything which 
is not a RegexpRef');
 ok(defined RegexpRef(qr/../),            '... RegexpRef accepts anything which 
is a RegexpRef');
 ok(!defined RegexpRef(bless {}, 'Foo'),  '... RegexpRef rejects anything which 
is not a RegexpRef');
+ok(!defined RegexpRef(bless {}, 'Regexp'), '... RegexpRef rejects anything 
which is not a RegexpRef');
 ok(!defined RegexpRef(undef),            '... RegexpRef rejects anything which 
is not a RegexpRef');
 
 ok(!defined GlobRef(0),                '... GlobRef rejects anything which is 
not a GlobRef');
@@ -301,7 +302,7 @@ ok(!defined Object($SCALAR_REF),      '... Object rejects 
anything which is not
 ok(!defined Object($GLOB),            '... Object rejects anything which is 
not blessed');
 ok(!defined Object($GLOB_REF),        '... Object rejects anything which is 
not blessed');
 ok(!defined Object($fh),              '... Object rejects anything which is 
not blessed');
-ok(!defined Object(qr/../),           '... Object rejects anything which is 
not blessed');
+ok(defined Object(qr/../),           '... Object accepts anything which is 
blessed');
 ok(defined Object(bless {}, 'Foo'),   '... Object accepts anything which is 
blessed');
 ok(!defined Object(undef),             '... Object accepts anything which is 
blessed');
 
-- 
1.7.3.3

Reply via email to