Tyil
Tyil

Reputation: 1807

How to implement around in Raku

In Perl, using Moo, you can implement around subs, which will wrap around other methods in a class.

around INSERT => sub {
    my $orig = shift;
    my $self = shift;

    print "Before the original sub\n";
    my $rv  = $orig->($self, @_);
    print "After the original sub\n";
};

How can this behaviour be implemented in Raku, preferably using a role?

Upvotes: 14

Views: 269

Answers (3)

Holli
Holli

Reputation: 5072

Method::Modifiers

Implements before(), after() and around() functions that can be used to modify class methods similarly to Perl 5's Moose. It uses wrap() internally, and returns the wrapper handler, so it is easy to .restore() the original.

This is how the module implements around:

sub around ($class, $method-name, &closure) is export
{
  $class.^find_method($method-name).wrap(method { closure(); });
}

Upvotes: 8

jjmerelo
jjmerelo

Reputation: 23517

Use wrap

sub bar () { return "baþ" };

my $wrapped = &bar.wrap( { " → " ~ callsame() ~ " ← " } );

say bar(); # OUTPUT:  «→ baþ ← »

Since methods are routines, you'll need a slightly more convoluted way to get a handle on the method itself, but other than that, the method is exactly the same, since Methods are a subclass of Routines

class Baz {
    method bar () { return "baþ" };
}

my &method_bar = Baz.^find_method("bar");
my $wrapped = &method_bar.wrap( { " → " ~ callsame() ~ " ← " } );

say Baz.bar(); # OUTPUT:  «→ baþ ← »

The $wrapped is a handle that can be used, later on, to unwrap it if needed.

Edit: to add the code to get a handle on the class method, taken from here, for instance.

Upvotes: 6

ugexe
ugexe

Reputation: 5726

You can shadow the method with the role and then use callwith:

class Foo {
    method meth { say 2 }
}

my $foo = Foo.new but role :: {
    method meth(|c) { say 1; callwith(|c); say 3 }
};

$foo.meth

Upvotes: 8

Related Questions