Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access the attributes of a class indirectly

This is similar to, but not quite the same as another of my questions: Content checking some, not all, class attributes

I am writing a test to verify the effect of processing on a object. But I can't work out how to get the value of a known set of the object's attributes but test with the same code. Something like the following (which does not work):

class A { has $.a, has $.b, has $.c };
my A $v .=new(:1a, :2b);

for <a b> { ok $v.{$_} > 0 }; # this does not work, but illustrates the intent.

If instead of an object I had used a Hash, then it is easy to get values from the Hash knowing the keys.

At the moment all I can think of is to test each attribute:

ok $v.a > 0;
ok $v.b > 0;

In addition, I don't want to look at ALL the attributes of the object, which is what .^attributes gives me, only some of them.

like image 836
Richard Hainsworth Avatar asked Aug 10 '20 11:08

Richard Hainsworth


People also ask

How do you access attributes of a class?

Attributes of a class can also be accessed using the following built-in methods and functions : getattr() – This function is used to access the attribute of object. hasattr() – This function is used to check if an attribute exist or not. setattr() – This function is used to set an attribute.

How do you find the attributes of an object in Python?

Python getattr() function is used to get the value of an object's attribute and if no attribute of that object is found, default value is returned. Basically, returning the default value is the main reason why you may need to use Python getattr() function.

How do you access class variables in Python?

Use class_name dot variable_name to access a class variable from a class method in Python. Use instance to access variables outside the class.


1 Answers

The issue you are encountering – and the reason tests like this are easier with Hashes than with Classes – is that you are passing in a Str when you need to pass in an object. This issue doesn't come up with Hashes because (by default), Hash keys already are strings.

The other important thing to remember is that, technically speaking, there isn't any way to directly access the attributes of a Raku object from outside of the object – Raku does not have public attributes, just attributes you can access from a public accessor method. This may seem like a pedantic distinction, but it's important here: it means that you need a callable Method object (which is more specific than the "object" I mentioned in the previous paragraph).

As Tyil mentioned in a comment, you can get Raku to dwym with the code for <a b> { ok $v."$_"() > 0 };. The reason this works is that the final () forces Raku to treat the interpolated value of "$_" as a Callable, which in this case means a Method.

However, I'd prefer to be slightly more explicit and use the following syntax:

for $v.^methods.grep({.name ~~ 'a' | 'b'}) { ok $_($v) > 0}

(This takes advantage of the fact that $object.method and method($object) are syntactically equivalent).

Note that we have the grep above because you wanted to test just some of A's methods. However, even if you want to test all of the methods you added to A, you may still need the grep to exclude BUILDALL, which is returned by $v.^methods(:local). I haven't figured out whether that is intentional or a bug (it doesn't seem like a local method) and would appreciate anyone's thoughts on that.

like image 159
codesections Avatar answered Oct 23 '22 13:10

codesections