Home > Raku > Chain calling

Chain calling

When working with IO::Path we have to take platform dependent directory separator into account. To alleviate the problem .add was added. Surprisingly there is no candidate that takes a list. So we have to chain method calls as if we would use an inferior language.

'/home/dex'.IO.chain.add('tmp').add('foo.txt').say;
"/home/dex/tmp/foo.txt".IO

Since it is rather unlikely that we ever do calculations with IO::Path objects we can repurpose infix:</>. Doing so gives us metaoperators for free.

multi sub infix:</>(IO::Path:D \p is raw, Str:D \s) {
    p.add(s).resolve()
}

multi sub infix:</>(IO::Path:D \p is copy, List:D \l) {
    for l {
        p = p.add: .Str
    }

    p
}

my $p = '/home/dex/'.IO;
$p /= 'bar';
dd $p;
# OUTPUT: Path $p = IO::Path.new("/home/dex/bar", :SPEC(IO::Spec::Unix), :CWD("/"))

Having to chain method calls because the implementer was lazynot overly imaginative is a common theme. Since the default parent class is Any, any method added to that class should show up everywhere.

use MONKEY-TYPING;

augment class Any {
    method chain {
        class Chainer {
            has $.the-object;
            method FALLBACK($name, *@a) {
                my $o = $.the-object;
                for @a -> $e {
                    $o = $o."$name"($e, |%_);
                }

                $o
            }
        }

        Chainer.new(the-object => self)
    }
}

IO::Path.HOW.compose(IO::Path);

'/home/dex'.IO.chain.add(<tmp foo.txt>).say;
# OUTPUT: "/home/dex/tmp/foo.txt".IO

The method chain actually breaks the chain by returning an instance of a private class. This object knows the original object and will change any method call to a loop over the first positional. Named arguments are forwarded via the implicit argument %_.

You likely spotted both “should” and .HOW.compose. This is a long-standing issue. The MOP does keep a list of parent classes but not for children. So neither the compiler nor we can easily walk all type objects to recompose them. It’s a bit of a shame. There is likely much more that could be done in raku.land with a properly working augment.

Categories: Raku