I often want to test that I've defined a method in a particular class. This has caught many problems where I've renamed a method or otherwise rearranged things in the architecture.
I know I can use .^lookup
but that still feels weird to me like I'm eventually going to run into a case where it returns things in a different order than I expect (ignore signatures for now). This is what I came up with:
use Test;
class Foo is Str {}
class Bar is Str { method Str { 'Hello' } }
can-ok Str, 'Str';
can-ok Foo, 'Str';
can-ok Bar, 'Str';
is Foo.^lookup( 'Str' ).package.^name, 'Foo', 'Foo defines Str';
is Bar.^lookup( 'Str' ).package.^name, 'Bar', 'Bar defines Str';
done-testing;
It does what I want in this simple case and I haven't made it fail so far:
ok 1 - The type 'Str' can do the method 'Str'
ok 2 - The type 'Foo' can do the method 'Str'
ok 3 - The type 'Bar' can do the method 'Str'
not ok 4 -
ok 5 -
1..5
# Failed test at /Users/brian/Desktop/hello.p6 line 12
# expected: 'Foo'
# got: 'Mu'
# Looks like you failed 1 test of 5
You should not be comparing types by name.
my \Foo = anon class Foo {}
my \Bar = anon class Foo {}
say Foo.^name eq Bar.^name; # True
say Foo eqv Bar; # False
In fact is
checks for object identity if you give it a type object as the second argument.
is Bar.^lookup( 'Str' ).package, Bar, 'Bar defines Str'
You could always add a subroutine to add clarity.
sub defines-method (
Mu:U $class,
Str:D $method,
Str:D $desc = "$class.^name() defines $method"
) {
is $class.^lookup( $method ).?package, $class, $desc
}
defines-method Foo, 'Str';
You could alias it to an operator
sub &infix:<defines-method> = &defines-method;
Bar defines-method 'Str';
(Note that I used .?package
in case .^lookup
doesn't return anything.)
.^lookup
gives you the Method object that will be called; so I don't know why you are talking about it giving you them in a different order when there is only one value returned. If there are multi methods it returns the proto method (possibly implicitly created).
If you want the individual multi methods you would call .candidates
on it.
(There is also .^find_method
, and off the top of my head I don't remember the difference)
I believe you are thinking of .can
which gives you the Method objects in the order they would be called if you used .*Str
or .+Str
, which is the same as the method resolution order. Which means it would only change if you change the inheritance tree.
> class Bar is Str { method Str { 'Hello' } }
> quietly .perl.say for Bar.+Str;
"Hello"
""
""
> .perl.say for Bar.new.+Str
"Hello"
""
"Bar<80122504>"
> quietly .(Bar).perl.say for Bar.can('Str')
"Hello"
""
""
> .(Bar.new).perl.say for Bar.can('Str')
"Hello"
""
"Bar<86744200>"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With