I am new to Perl 6. I have the following code in my Atom Editor, but I still don't understand how this works. I copied the following code, as the doc.perl6.org said, but it seems that it does not work. So I changed the code to this:
use v6;
class HTTPHeader { ... }
class HTTPHeader does Associative {
has %!fields handles <self.AT-KEY self.EXISTS-KEY self.DELETE-KEY self.push
list kv keys values>;
method Str { say self.hash.fmt; }
multi method EXISTS-KEY ($key) { %!fields{normalize-key $key}:exists }
multi method DELETE-KEY ($key) { %!fields{normalize-key $key}:delete }
multi method push (*@_) { %!fields.push: @_ }
sub normalize-key ($key) { $key.subst(/\w+/, *.tc, :g) }
method AT-KEY (::?CLASS:D: $key) is rw {
my $element := %!fields{normalize-key $key};
Proxy.new(
FETCH => method () { $element },
STORE => method ($value) {
$element = do given $value».split(/',' \s+/).flat {
when 1 { .[0] } # a single value is stored as a string
default { .Array } # multiple values are stored as an array
}
}
);
}
}
my $header = HTTPHeader.new;
say $header.WHAT; #-> (HTTPHeader)
"".say;
$header<Accept> = "text/plain";
$header{'Accept-' X~ <Charset Encoding Language>} = <utf-8 gzip en>;
$header.push('Accept-Language' => "fr"); # like .push on a Hash
say $header.hash.fmt;
"".say;
say $header<Accept-Language>.values;
say $header<Accept-Charset>;
the output is:
(HTTPHeader)
Accept text/plain
Accept-Charset utf-8
Accept-Encoding gzip
Accept-Language en fr
(en fr)
utf-8
I konw it works, but the document in doc.perl6.org is a little different to this, which doesn't have "self" before the AT-KEY method in the 7th line. Is there any examples that more detail about this?
Is there any examples that more detail about this?
Stack overflow is not really the place to request more detail on a published example. This is the perl6 doco on the community itself - I would suggest that the most appropriate place if you have further queries is the Perl6 users mailing list or, failing that, the IRC channel, perhaps.
Now that you've posted it though, I'm hesitant to let the question go unaddressed so, here are a couple of things to consider;
Firstly - the example you raised is about implementing associative subscripting on a custom (ie user defined) class - it's not typical territory for a self-described newbie. I think you would be better off looking at and implementing the examples at Perl6 intro by Naoum Hankache whose site has been very well received.
Option 1 - Easy implementation via delegation
Secondly, it's critical to understand that the example is showing three options for implementing associative subscripting; the first and simplest uses delegation to a private hash attribute. Perl6 implements associative and positional subscripts (for built-in types) by calling well-defined methods on the object implementing the collection type. By adding the handles
trait on the end of the definition of the %!fields
attribute, you're simply passing on these method calls to %!fields
which - being a hash - will know how to handle them.
Option 2 - Flexible keys
To quote the example:
However, HTTP header field names are supposed to be case-insensitive (and preferred in camel-case). We can accommodate this by taking the *-KEY
and push
methods out of the handles list, and implementing them separately...
Delegating all key-handling methods to the internal hash means you get hash-like interpretation of your keys - meaning they will be case-sensitive as hash keys are case-sensitive. To avoid that, you take all key-related methods out of the handles clause and implement them yourself. In the example, keys are ran through the "normalizer" before being used as indexes into %!fields
making them case-insensitive.
Option 3 - Flexible values
The final part of the example shows how you can control the interpretation of values as they go into the hash-like container. Up to this point, values supplied by assigning to an instance of this custom container had to either be a string or an array of strings. The extra control is achieved by removing the AT_KEY method defined in option 2 and replacing it with a method that supplies a Proxy Object. The proxy object's STORE method will be called if you're assigning to the container and that method scans the supplied string value(s) for ", " (note: the space is compolsory) and if found, will accept the string value as a specification of several string values. At least, that's what I think it does.
So, the example has a lot more packed into it than it looks. You ran into trouble - as Brad pointed out in the comments - because you sort-of mashed option 1 togeather with option 3 when you coppied the example.