I was playing the buffers and reading binary data but I ended up implementing a Perl 6 version of hexdump. Looking for a place to put it, I figured Perl6PowerTools might as well exist. Now it has a single program, but I figure there are people who will look at the original PerlPowerTools and want to translate some of those to Perl 6.
There’s quite a bit going on in the program, but I’ll pull out just a bit of it.
my @options = qw/ C c d b o x /.grep: { $::($_) }; while my Buf $buf = $fh.read( octets_to_read( $counter, $n ) ) { # You can select more than one option at a time # change the option order to change the output order # These correspond to the named Bool parameters in the signature for @options -> $option { put $counter.fmt( '%08x ' ), &::("show_$option")($buf); } $counter += $buf.elems; last if $n && $counter >= $n; }
I implemented the -C
, -c
, -d
, -b
, -o
, and -x
switches. Each of these present the data in a different way, making all the combinations of octet or words with octal, decimal, or hexadecimal.
Surprisingly, the hexdump I have on my Mac will happily do all of these at once. That means I have it a bit easier since I don’t have to create an option processing hierarchy to exclude others. I figured that Perl 6’s multi methods would be good for that, which is one of the reasons I started writing the program. Even when I found out I didn’t need that I kept going.
So, on each group of octets that I read, I have the opportunity to print several lines. I need to check which options are set to True. I could do that with a lot of repeated code:
put $counter.fmt( '%08x ' ), show_C($buf) if $C; put $counter.fmt( '%08x ' ), show_c($buf) if $c; put $counter.fmt( '%08x ' ), show_d($buf) if $d; ...
Instead, I use a variable to decide the variable name with $::($some_variable)
. I filter out all the ones that are False:
my @options = qw/ C c d b o x /.grep: { $::($_) };
When it’s time to output something, I go through the options that I have left. Each one has an associated subroutine, which I lookup in the same way:
for @options -> $option { put $counter.fmt( '%08x ' ), &::("show_$option")($buf); }
I also thought of translating those subroutine lookups beforehand but I didn’t get that far. I don’t really need to keep constructing the subroutine name. That’s something I can fix later.
There’s something that’s probably surprising to Perl 5 people. This little trick isn’t limited to a particular set of variables. It works with lexicals too:
my $foo = "Some value"; put "The value of \$foo is ", $::('foo'); # works just fine.