about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2020-12-17 10:45:12 +0000
committerEric Wong <e@80x24.org>2020-12-19 09:32:08 +0000
commit7e7f4bfca5f2ef0d123445e074280f5e65cdfb85 (patch)
tree591d12f8dce7c43a5fac167b10481bcaa83b2f03
parent68fea5b055787c65f0e7164cbd5463f140382ea9 (diff)
downloadpublic-inbox-7e7f4bfca5f2ef0d123445e074280f5e65cdfb85.tar.gz
This is a localized version of the process-wide END{}, but runs
at the end of variable scope.  A subroutine ref and arguments
may be passed, which allows us to avoid anonymous subs and
problems they cause.

It's similar to `defer' or `ensure' in other languages; Perl can
rely on deterministic destructors due to refcounting.
-rw-r--r--MANIFEST2
-rw-r--r--lib/PublicInbox/OnDestroy.pm16
-rw-r--r--t/on_destroy.t25
3 files changed, 43 insertions, 0 deletions
diff --git a/MANIFEST b/MANIFEST
index 29b47843..8e870c22 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -181,6 +181,7 @@ lib/PublicInbox/NNTP.pm
 lib/PublicInbox/NNTPD.pm
 lib/PublicInbox/NNTPdeflate.pm
 lib/PublicInbox/NewsWWW.pm
+lib/PublicInbox/OnDestroy.pm
 lib/PublicInbox/Over.pm
 lib/PublicInbox/OverIdx.pm
 lib/PublicInbox/ProcessPipe.pm
@@ -343,6 +344,7 @@ t/nntpd-v2.t
 t/nntpd.t
 t/nodatacow.t
 t/nulsubject.t
+t/on_destroy.t
 t/over.t
 t/plack-2-txt-bodies.eml
 t/plack-attached-patch.eml
diff --git a/lib/PublicInbox/OnDestroy.pm b/lib/PublicInbox/OnDestroy.pm
new file mode 100644
index 00000000..841f87d4
--- /dev/null
+++ b/lib/PublicInbox/OnDestroy.pm
@@ -0,0 +1,16 @@
+# Copyright (C) 2020 all contributors <meta@public-inbox.org>
+# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
+
+package PublicInbox::OnDestroy;
+
+sub new {
+        shift; # ($class, $cb, @args)
+        bless [ @_ ], __PACKAGE__;
+}
+
+sub DESTROY {
+        my ($cb, @args) = @{$_[0]};
+        $cb->(@args) if $cb;
+}
+
+1;
diff --git a/t/on_destroy.t b/t/on_destroy.t
new file mode 100644
index 00000000..8b85b48e
--- /dev/null
+++ b/t/on_destroy.t
@@ -0,0 +1,25 @@
+#!perl -w
+use strict;
+use v5.10.1;
+use Test::More;
+require_ok 'PublicInbox::OnDestroy';
+my @x;
+my $od = PublicInbox::OnDestroy->new(sub { push @x, 'hi' });
+is_deeply(\@x, [], 'not called, yet');
+undef $od;
+is_deeply(\@x, [ 'hi' ], 'no args works');
+$od = PublicInbox::OnDestroy->new(sub { $x[0] = $_[0] }, 'bye');
+is_deeply(\@x, [ 'hi' ], 'nothing changed while alive');
+undef $od;
+is_deeply(\@x, [ 'bye' ], 'arg passed');
+$od = PublicInbox::OnDestroy->new(sub { @x = @_ }, qw(x y));
+undef $od;
+is_deeply(\@x, [ 'x', 'y' ], '2 args passed');
+
+if (my $nr = $ENV{TEST_LEAK_NR}) {
+        for (0..$nr) {
+                $od = PublicInbox::OnDestroy->new(sub { @x = @_ }, qw(x y));
+        }
+}
+
+done_testing;