Rand Stats

CompUnit::Util

zef:lizmat

Actions Status Actions Status Actions Status

NAME

CompUnit::Util - Utilities for introspecting compunits and re-exporting

SYNOPSIS

use CompUnit::Util;

DESCRIPTION

CompUnit::Util contains set of utilities to introspect CompUnit stuff and a bunch of compile time symbol manipulation tools. Its main purpose is to encapsulate the compiler hacks needed to implement features like 're-exporting' which don't exist in rakudo yet.

WARNING this module relies on unspec'd rakudo internals and can (and has and will) break without warning.

CompUnit UTILITIES

CompUnit introspection utilities.

Apart from load none of the routines here will load a compunit. All parameters named $handle are converted to a CompUnit::Handle object automatically. If the $handle you pass is not a defined CompUnit or CompUnit::Handle, &find-loaded will be used toi search for a loaded compunit matching it.

load

use CompUnit::Util :load;
my CompUnit $cu = load('Test');
# or even
my $cu = load('MyModule', version => v3);

Loads a compunit by name. All named arguments to CompUnit::DependencySpecification are accepted (other than short-name which is the positional argument). At the moment load is just short for:

$*REPO.need(CompUnit::Dependencyspecification.new(:short_name<MyModule>));

find-loaded

use CompUnit::Util :find-loaded;
need SomeModule;
my CompUnit $some-module = find-loaded('SomeModule');

Searches all the CompUnit::Repositorys until it finds a loaded compunit matching $match. Returns a failure otherwise.

all-loaded

use CompUnit::Util :all-loaded;
.note for all-loaded;

Returns all loaded CompUnits.

at-unit

use CompUnit::Util :at-unit;
say at-unit('CompUnit::Util','$=pod');

Gets a symbol from the UNIT scope of the compunit. If you want to do this at compile time while a compunit is loading see get-unit.

unit-to-hash

use CompUnit::Util :unit-to-hash;
my %unit := unit-to-hash('SomeModule');

Returns a Hash representing the UNIT:: of the module.

capture-import

use CompUnit::Util :capture-import;
need SomeModule;
my %symbols = capture-import('SomeModule',:tag);

Attempts to simulate a use statement. Returns a hash of all the symbols the compunit would export if it were used.

WHO Utilities

set-in-WHO

use CompUnit::Util :who;
my package Example {};
BEGIN set-in-WHO(Example.WHO,'Foo::Bar::$Baz','win');

say Example::Foo::Bar::<$Baz>; #-> win

Convenience routine for setting a symbol's value inside a package that might not exist yet. Only useful outside the compunit being compiled.

descend-WHO

use CompUnit::Util :who;
my package Example {};
BEGIN set-in-WHO(Example.WHO,'Foo::Bar::Baz','win');
BEGIN note descend-WHO(Example.WHO,'Foo::Bar::Baz'); #-> win

Convenience routine for getting a symbol's value with a path from a Stash like .WHO. Only useful outside the currently compiling compunit (where you can just use the normal syntax).

Re-Exporting

The following routines provide re-exporting which is not yet implemented in rakudo.

re-export

This routine can only be called at BEGIN time

use CompUnit::Util :re-export;
need SomeModule;
BEGIN re-export('SomeModule');
# This compunit will now export everything that SomeModule does

Merges the EXPORT package from $handle into the present UNIT::EXPORT.

re-exporthow

This routine can only be called at BEGIN time

use CompUnit::Util :re-export;
need SomeModule;
BEGIN re-exporthow('SomeModule');
# This compunit now exports SomeModule's custom declarators

Merges the EXPORTHOW from $handle into the present UNIT::EXPORTHOW. UNIT::EXPORTHOW will be created if it doesn't exist but it won't clobber it if it does.

steal-export-sub

This routine can only be called at BEGIN time

use CompUnit::Util :re-export;
need SomeModule;
BEGIN steal-export-sub('SomeModule');
# This compunit now has the same &EXPORT as SomeModule

Sets UNIT::<&EXPORT> to $handle's &EXPORT.

steal-globalish

This routine can only be called at BEGIN time

use CompUnit::Util :re-export,:load;
BEGIN steal-globalish(load('SomeModule'));
# This compunit now has everything in SomeModule in it's globalish

Merges the GLOBALish from $handle into the present UNIT::GLOBALish.

This is the least interesting of all the re-exports, and if you've already done need SomeModule; you won't need it. But it's here for completeness. The above example should be the same as this anyway:

BEGIN require ::('SomeModule');

re-export-everything

This routine can only be called at BEGIN time

use CompUnit::Util :re-export;
BEGIN re-export-everything('SomeModule');
# use [this-module]; should now do the same thing as use SomeModule;

A convenience method for calling all the other functions under re-export functions with the same argument.

SYMBOL SETTING

The following routines manipulate the symbols of the compunit being compiled. They are probably of most use inside an &EXPORT sub or in a trait.

They each take a map of symbol names to values and install them in different places.

NOTE: These subs will overwrite existing symbols without warning.

Inserts name/value pairs into the present UNIT::EXPORT under $tag.

set-unit

This routine can only be called at BEGIN time

# like is export, but prefixes the the exported name with 'fun-'
sub trait_mod:<is>(Routine:D $r, :$export-fun!) {
    my $exported-name = '&fun-' ~ $r.name;
    set-unit("EXPORT::DEFAULT::{$exported-name}",$r);
    {};}

Inserts the $value at $path in UNIT of the currently compiling compunit.

set-lexpad

This routine can only be called at BEGIN time

The same as set-unit but inserts the $value into the lexical scope being compiled.

SYMBOL GETTING

get-unit

use CompUnit::Util :get-symbols;
sub foo is export { };
BEGIN note get-unit('EXPORT::DEFAULT::&foo') === &foo; #-> True

get-lexpad

The same as get-unit but looks for the symbol in the lexpad being compiled.

get-lexical

Like get-lexpad but does a full lexical lookup. At the moment it can only take a single $name with no ::.

DISPATCHER MANIPULATION

These routines help you construct multi dispatchers candidate by candidate in a procedural manner. Useful when you want to construct a trait that adds a multi candidate each time it's called. Parameters marked $multi can be any Routine:D. If you pass a dispatcher it will just use it as the dispatcher or die if you are trying to push onto an existing dispatcher.

If you try and push a non-multi/dispatcher onto an empty slot it will not vivify one for you.

push-multi

Adds the $candidate onto $target.

use CompUnit::Util :push-multi;
multi foo('one') { 'one' }
multi foo('two') { 'two' }

&foo.&push-multi(sub ('three') { "win" });
say foo('three') #-> "win"

NOTE: This is NYI in rakudo. The design docs says that protos should have a .push method. See S06.

push-unit-multi

This routine can only be called at BEGIN time

## lib/SillyModule.rakumod
use CompUnit::Util :push-multi
# exports the multi under a sub named after its first letter
sub trait_mod:<is>(Routine:D $r,:$one-letter-export!) {
    my $exported-name = '&' ~ $r.name.comb[0];
    push-unit-multi("EXPORT::DEFAULT::{$exported-name}",$r);
}

multi bar(Str) is one-letter-export { say "bar" }
multi baz(Int) is one-letter-export { say "baz" }

...
use SillyModule;

b("string"); #-> bar
b(1) #-> baz

Takes $multi and pushses it onto a dispatcher located at $path. If one doesn't exist it will be created. You can pass a proto instead of a multi but only when $path is empty (ie only the first time). It will become the dispatcher for any further calls.

push-lexpad-multi

This routine can only be called at BEGIN time

The same as push-unit-multi but pushes onto a symbol in the lexical scope currently being compiled.

push-lexical-multi

This routine can only be called at BEGIN time

The smart version of push-lexpad-multi. If it doesn't find a dispatcher in the current lexpad it will do a lexical lookup for one of the same $name. If it finds one it clones it, installs it in the current lexpad and pushes $multi onto it. Like get-lexical, it can't take a $name with :: in it.

AUTHOR

Lloyd Fournier

Source can be located at: https://github.com/raku-community-modules/CompUnit-Util . Comments and Pull Requests are welcome.

COPYRIGHT AND LICENSE

Copyright 2016 - 2023 Lloyd Fournier

Copyright 2026 Raku Community

This library is free software; you can redistribute it and/or modify it under MIT License.