Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom exception classes [rt.cpan.org #73316] #92

Open
toddr opened this issue Jan 16, 2020 · 1 comment
Open

Custom exception classes [rt.cpan.org #73316] #92

toddr opened this issue Jan 16, 2020 · 1 comment
Labels

Comments

@toddr
Copy link
Collaborator

toddr commented Jan 16, 2020

Migrated from rt.cpan.org#73316 (status was 'new')

Requestors:

Attachments:

From [email protected] on 2011-12-16 14:02:42
:

Using custom exception classes for autodie fails if the packages are
defined inline and do not reside in a separate file.

I have attached a patch with a testcase as well as a possible fix.

@toddr
Copy link
Collaborator Author

toddr commented Jan 16, 2020

Patch:

diff --git a/lib/Fatal.pm b/lib/Fatal.pm
index aabdf78..c314a2a 100755
--- a/lib/Fatal.pm
+++ b/lib/Fatal.pm
@@ -1234,13 +1234,7 @@ sub exception_class { return "autodie::exception" };
             # actually barewords.  As such, we're left doing a string eval
             # to make sure we load our file correctly.
 
-            my $E;
-
-            {
-                local $@;   # We can't clobber $@, it's wrong!
-                eval "require $exception_class"; ## no critic
-                $E = $@;    # Save $E despite ending our local.
-            }
+            my $E = _load_class($exception_class);
 
             # We need quotes around $@ to make sure it's stringified
             # while still in scope.  Without them, we run the risk of
@@ -1256,6 +1250,35 @@ sub exception_class { return "autodie::exception" };
     }
 }
 
+# Smarter loading of exception classes
+
+sub _load_class {
+    my ($class) = @_;
+
+    {
+        no strict 'refs';
+
+        # Handle by far the two most common cases
+        # This is very fast and handles 99% of cases.
+        return if defined ${"${class}::VERSION"};
+        return if defined @{"${class}::ISA"};
+    
+        # Are there any symbol table entries other than other namespaces
+        foreach ( keys %{"${class}::"} ) {
+            next if substr($_, -2, 2) eq '::';
+            return if defined &{"${class}::$_"};
+        }
+    }
+
+    local $@;   # We can't clobber $@, it's wrong!
+    
+    my $pm_file = $class . ".pm";
+    $pm_file =~ s{ (?: :: | ' ) }{/}gx;
+    eval { require $pm_file };
+    
+    return $@;    # Return $E despite ending our local.
+}
+
 # For some reason, dying while replacing our subs doesn't
 # kill our calling program.  It simply stops the loading of
 # autodie and keeps going with everything else.  The _autocroak

@toddr toddr added the HasPatch label Dec 28, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant