13

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?

jjmerelo
  • 22,578
  • 8
  • 40
  • 86
Tyil
  • 1,797
  • 9
  • 14

3 Answers3

8

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
ugexe
  • 5,297
  • 1
  • 28
  • 49
8

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(); });
}
Holli
  • 5,072
  • 10
  • 27
6

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.

jjmerelo
  • 22,578
  • 8
  • 40
  • 86
  • Wrap doesn't wrap methods – ugexe Nov 06 '19 at 17:11
  • @ugexe the OP refers explicitly to subs. Also, you can just use that for methods, since it's a [`Method` is a `Routine`](https://docs.raku.org/type/Method) – jjmerelo Nov 06 '19 at 17:11
  • I think you're confused. The question itself states 'wrap around other methods in a class.'. `Moo`s around is nothing like wrapping a subroutine. – ugexe Nov 06 '19 at 17:13
  • @ugexe same difference. Methods are Routines, as I said after the edit. – jjmerelo Nov 06 '19 at 17:17