
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.