Perl 5.10 gives us UNITCHECK. So now we have CHECK that works at program level, UNITCHECK that narrows it down to a unit (e.g. a module/file). The next step is to narrow it down further to a lexical scope. That's what this module does.

A problem with UNITCHECK blocks as of today is that there's no way for a module to add a UNITCHECK to the unit that uses the module, making the use quite limited. Until there's a solution to that (if there will be), Scope::CHECK is an IMHO good enough alternative. Most modules are used at file scope, and modules that need to use this module shouldn't be dynamically loaded.

Here's a minimal demonstration of lexical CHECK blocks that pin-points where the block is executed:

use 5.010; use Scope::CHECK; { BEGIN { Scope::CHECK::->add(sub { say 'Checking scope' }) } BEGIN { say 'End of scope' } } BEGIN { say 'After scope' } __END__ End of scope Checking scope After scope

The complete .pm file is found below.

Update: It looks as though I've found a way to stop blocks to run prematurely due to threads. (See the BUGS section in the POD for the issue.)

Update: The verdict from p5p is that this is explicitly not supported.

package Scope::CHECK; use 5.010; $VERSION = 0.001; use strict; { package Scope::CHECK::_OnScopeExit; sub new { bless $_[1], $_[0] } DESTROY { goto &{$_[0]} } } sub add { state @queue; state $Id = 0; shift; my ($code) = @_; push @queue, $code; $^H{__PACKAGE__ . '::_' . $Id++} = Scope::CHECK::_OnScopeExit::->new(sub { (pop @queue)->() }); } 1; __END__ =head1 NAME Scope::CHECK - Add CHECK blocks to the currently compiling lexical sco +pe =head1 SYNOPSIS use 5.010; use strict; use Scope::CHECK; { BEGIN { say '1. Compiling block.' } BEGIN { Scope::CHECK::->add(sub { say '4. Checking block, again.' +}); } BEGIN { Scope::CHECK::->add(sub { say '3. Checking block.' }); } BEGIN { say '2. Done compiling block.' } } BEGIN { say '5. Compiling rest of file.' } say '6. Running file.'; __END__ 1. Compiling block. 2. Done compiling block. 3. Checking block. 4. Checking block, again. 5. Compiling rest of file. 6. Running file. =head1 DESCRIPTION C<Scope::CHECK> lets you add C<CHECK> blocks to the currently compilin +g lexical scope. You probably want to do this because you need to def +er code until the whole scope is done compiling. C<Scope::CHECK> blocks run in LIFO order, just as C<CHECK> and C<UNITC +HECK> blocks. C<Scope::CHECK> blocks at "unit scope", i.e. the same lexical scope as + C<UNITCHECK> lives in, currently execute before C<UNITCHECK> blocks. + This depends on the inner working of perl, and this order isn't defi +ned anywhere as far as I know. =head1 METHODS =over =item Scope::CHECK->add(CODE) C<add> takes a subroutine reference as the only argument. The subrouti +ne will be executed when the currently compiling lexical scope is com +piled. =back =head1 BUGS =over =item Not really C<CHECK> blocks As the blocks aren't really C<CHECK> blocks but only pretend to be, th +ey might be executed too early before all compile passes are done. I +don't know before/during/after which compile pass they're executed. I +f you don't use C<Scope::CHECK> blocks to manipulate the optree you'r +e probably safe. Let me know if you have any problems related to this +. =item Threads C<Scope::CHECK> may not work in combination with threads. As long as y +ou don't B<start> any threads while a C<Scope::CHECK> block is waitin +g to execute or inside a C<Scope::CHECK> block you probably won't hav +e any problem. Here's an example of what can happen when you start a +thread before an active C<Scope::CHECK> block has been executed: use 5.010; use strict; use Scope::CHECK; use threads; { BEGIN { Scope::CHECK::->add(sub { say 'CHECK' }) } BEGIN { threads::->create(sub { say 'Thread started and ended. +' })->join } BEGIN { say 'Block compiled.' } } BEGIN { say 'Continuing compiling.' } __END__ Thread started and ended. CHECK Block compiled. CHECK Continuing compiling. Notice the extra CHECK in the output. The first is because the thread +ended, and the block was thus run prematurely. If you find any way to detect that a block executed because a thread e +nded, please let me know. =item When no scope is compiling If no scope is being compiled the block will be executed when the prog +ram exits, after C<END> blocks. This is not by design but due to curr +ent implementation. =back =head1 AUTHOR lodin =head1 COPYRIGHT Copyright 2008 lodin. All rights reserved. This library is free software; you can redistribute it and/or modify i +t under the same terms as Perl itself. =head1 SEE ALSO L<perlmod> for C<CHECK> and C<UNITCHECK>. =cut

lodin


In reply to RFC: Scope::CHECK - Add CHECK blocks to the currently compiling lexical scope by lodin

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.