Home > Raku > MAIN course

MAIN course

On IRC vasko asked how to handle a --verbose-flag. This is quite simple.

sub debug($level, |c) {
    say(|c) if $*VERBOSE && $*DEBUG-LEVEL ≥ $level;
}

sub MAIN(:v(:verbose($*VERBOSE)), :D(:debug-level($*DEBUG-LEVEL))) {
    debug 1, 'FYI, all is fine';
}

I can spot two pieces laying on our boilerplate. If you do a lot of shell-scripting, supporting -v and -D might be quite common. Also, every time we call debug we type a space and a comma to many.

proto sub MAIN(Bool :v(:verbose($*VERBOSE)) = False, Int :D(:debuglevel($*DEBUG-LEVEL)) = 1, |) is export {
    &debug1 = &debug.assuming(1) if $*DEBUG-LEVEL ≥ 1;
    &debug2 = &debug.assuming(2) if $*DEBUG-LEVEL ≥ 2;
    &debug3 = &debug.assuming(3) if $*DEBUG-LEVEL ≥ 3;
    &debug4 = &debug.assuming(4) if $*DEBUG-LEVEL ≥ 4;
    &debug5 = &debug.assuming(5) if $*DEBUG-LEVEL ≥ 5;
    &debug6 = &debug.assuming(6) if $*DEBUG-LEVEL ≥ 6;
    &debug7 = &debug.assuming(7) if $*DEBUG-LEVEL ≥ 7;
    &debug8 = &debug.assuming(8) if $*DEBUG-LEVEL ≥ 8;
    &debug9 = &debug.assuming(9) if $*DEBUG-LEVEL ≥ 9;

    my &*debug1 = &debug.assuming(1);

    {*}
}

sub debug($level, |c) {
    say(|c) if $*VERBOSE; # and $*DEBUG-LEVEL ≥ $level;
}

my (&debug1, &debug2, &debug3, &debug4, &debug5, &debug6, &debug7, &debug8, &debug9) X= {;};


sub EXPORT() {
    Map.new: '&debug1' => &debug1, '&debug2' => &debug2, '&debug3' => &debug3, '&debug4' => &debug4, '&debug5' => &debug5, '&debug6' => &debug6, '&debug7' => &debug7, '&debug8' => &debug8, '&debug9' => &debug9
}

This module exports a sub for each log-level. Those default to an empty block, until MAIN is called. Depending on the log-level, we rebind them to the actual sub debug with a fitting .assuming. We also wire up the dynvar $*VERBOSE. I wrote them in all caps to indicate they are constant-ish. This all works because an export of the form '&debug1' => &debug1 does export an &-sigiled container, which we can change even after sub EXPORT and the use-statement have finished their work.

use fancy-debug;

multi sub MAIN(*%_) {
    debug1 'level1';
    debug2 'level2';

    say 'i haz a done!';
}

Since we supply extra named arguments that are handled in the proto, we have to please the dispatcher with *%_. Repeating the named arguments would work too.

Thanks to vasko, I could identify dynvars in argument aliases as an ENODOC and found a way new way to remove the MAIN-course from my boilerplate.

Categories: Raku
  1. No comments yet.
  1. December 13, 2021 at 21:57

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: