The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Devel::Pragma - helper functions for developers of lexical pragmas

SYNOPSIS

  package MyPragma;

  use Devel::Pragma qw(:all);

  sub import {
      my ($class, %options) = @_;
      my $hints = my_hints;   # lexically-scoped %^H
      my $caller = ccstash(); # currently-compiling stash

      unless ($hints->{MyPragma}) { # top-level
           $hints->{MyPragma} = 1;

           # disable/enable this pragma before/after compile-time requires
           on_require \&teardown, \&setup;
      }

      if (new_scope($class)) {
          ...
      }

      my $scope_id = scope();
  }

DESCRIPTION

This module provides helper functions for developers of lexical pragmas. These can be used both in older versions of perl (from 5.8.1), which have limited support for lexical pragmas, and in the most recent versions, which have improved support.

EXPORTS

Devel::Pragma exports the following functions on demand. They can all be imported at once by using the :all tag. e.g.

    use Devel::Pragma qw(:all);

my_hints

Until perl change #33311, which isn't currently available in any stable perl release, values set in %^H are visible in files compiled by use, require and do FILE. This makes pragmas leak from the scope in which they're meant to be enabled into scopes in which they're not. my_hints fixes that by making %^H lexically scoped i.e. it prevents %^H leaking across file boundaries.

my_hints installs versions of perl's require and do FILE builtins in the currently-compiling scope which clear %^H before they execute and restore its values afterwards. Thus it can be thought of a lexically-scoped backport of change #33311.

Note that my_hints also sets the $^H bit that "localizes" (or in this case "lexicalizes") %^H.

The return value is a reference to %^H.

new_scope

This function returns true if the currently-compiling scope differs from the scope being compiled the last time new_scope was called. Subsequent calls will return false while the same scope is being compiled.

new_scope takes an optional parameter that is used to uniquely identify its caller. This should usually be supplied as the pragma's class name unless new_scope is called by a module that is not intended to be subclassed. e.g.

    package MyPragma;

    sub import {
        my ($class, %options) = @_;

        if (new_scope($class)) {
            ...
        }
    }

If not supplied, the identifier defaults to the name of the calling package.

scope

This returns an integer that uniquely identifies the currently-compiling scope. It can be used to distinguish or compare scopes.

A warning is issued if scope (or new_scope) is called in a context in which it doesn't make sense i.e. if the scoped behaviour of %^H has not been enabled - either by explicitly modifying $^H, or by calling "my_hints" or "on_require".

ccstash

This returns the name of the currently-compiling stash. It can be used as a replacement for the scalar form of caller to provide the name of the package in which use MyPragma is called. Unlike caller, it returns the same value regardless of the number of intervening calls before MyPragma::import is reached.

e.g. given a pragma:

    package MySuperPragma;

    use Devel::Hints qw(ccstash);

    sub import {
        my ($class, %options) = @_;
        my $caller = ccstash();

        no strict 'refs';

        *{"$caller\::whatever"} = ... ;
    }

and a subclass:

    package MySubPragma

    use base qw(MySuperPragma);

    sub import {
        my ($class, %options) = @_;
        $class->SUPER::import(...);
    }

and a script that uses the subclass:

    #!/usr/bin/env perl

    use MySubPragma;

- the ccstash call in MySuperPragma::import returns the name of the package that's being compiled when the call to MySuperPragma::import (via MySubPragma::import) takes place i.e. main in this case.

fqname

Given a subroutine name, usually supplied by the caller of the pragma's import method, this function returns the name in package-qualified form. In addition, old-style ' separators are converted to new-style ::.

If the name contains no separators, then the optional calling package is prepended. If not supplied, the caller defaults to the value returned by "ccstash". If the name is already package-qualified, then it is returned unchanged.

In list context, fqname returns the package and unqualified subroutine name (e.g. 'main' and 'foo'), and in scalar context it returns the package and sub name joined by '::' (e.g. 'main::foo').

e.g.

    package MyPragma;

    sub import {
        my ($class, @names) = @_;

        for my $name (@names) {
            my $fqname = fqname($name);
            say $fqname;
        }
    }

    package MySubPragma;

    use base qw(MyPragma);

    sub import { shift->SUPER::import(@_) }

    #!/usr/bin/env perl

    use MyPragma qw(foo Foo::Bar::baz Foo'Bar'baz Foo'Bar::baz);

    {
        package Some::Other::Package;

        use MySubPragma qw(quux);
    }

prints:

    main::foo
    Foo::Bar::baz
    Foo::Bar::baz
    Foo::Bar::baz
    Some::Other::Package::quux

on_require

This function allows pragmas to register pre- and post-require (and do FILE) callbacks. These are called whenever require or do FILE OPs are executed at compile-time, typically via use statements.

on_require takes two callbacks (i.e. anonymous subs or sub references), each of which is called with a reference to %^H. The first callback is called before require, and the second is called after require has loaded and compiled its file. %^H is cleared before require and restored afterwards. (If the file has already been loaded, or the required value is a vstring rather than a file name, then both the callbacks and the clearance/restoration of %^H are skipped.)

Multiple callbacks can be registered in a given scope, and they are called in the order in which they are registered. Callbacks are unregistered automatically at the end of the (compilation of) the scope in which they are registered.

on_require callbacks can be used to disable/re-enable OP check hooks installed via B::Hooks::OP::Check i.e. they can be used to make check hooks lexically-scoped.

    package MyPragma;

    use Devel::Pragma qw(:all);

    sub import {
        my ($class, %args) = @_;
        my $hints = my_hints;

        unless ($hints->{MyPragma}) { # top-level
            $hints->{MyPragma} = 1;
            on_scope_end \&teardown;
            on_require \&teardown, \&setup;
            setup;
        }
    }

on_require callbacks can also be used to rollback/restore lexical side-effects i.e. lexical features whose side-effects extend beyond %^H (like "my_hints", on_require implicitly renders %^H lexically-scoped).

Fatal exceptions raised in on_require callbacks are trapped and reported as warnings. If a fatal exception is raised in the require or do FILE call, the post-require callbacks are invoked before that exception is thrown.

VERSION

0.54

SEE ALSO

AUTHOR

chocolateboy <chocolate@cpan.org>

COPYRIGHT AND LICENSE

Copyright (C) 2008-2010 by chocolateboy

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.1 or, at your option, any later version of Perl 5 you may have available.