As i can see, your problem can be limited to finding a better way to create and document 'unpack' templates.
I myself would do it in an OO way (let's call the class for format templates 'Unpack::Format'):
my $format = Unpack::Format->new( spec =>[
status => 'n', # 0
time => 'n', # 2
date => 'N', # 4
code => 'a16', # 8 key
msid => 'a10', # 24 key
]
);
#overloaded
@test_vals{ @$format } = unpack "$format", $rec;
# pure OO style
@test-vals{$format->fieldnames) = unpack $format->templatestr, $rec;
It's easy to implement, and i think it's a much more clear way to create templates than using constants for field names and unpack string.
UPD: according to Hofmator's note, name-format pairs must be passed as an array reference. It seems to be a very easy typo to make :)
UPDATE 2: Working implementation (tested)
#!/usr/bin/perl
package Unpack::Format;
use warnings;
use strict;
use Carp;
use overload
'""' => \&templatestr,
'@{}' => \&fieldnames;
sub new {
my $class = shift;
my $self = {};
bless $self, $class;
@_ % 2 and croak "Odd number of parameters passed to ".__PACKAGE__
+."::new!";
my %params = @_;
$self->_load_fields($params{spec});
return $self;
}
sub _load_fields {
my $self = shift;
my $spec = shift;
@$spec % 2 and croak "Incorrect format specification: odd number o
+f elements";
$self->{fieldnames} = [@{$spec}[grep { !($_ %2) } 0..$#{$spec}]];
$self->{template_ary} = [@{$spec}[grep { $_ %2 } 0..$#{$spec}]];
}
sub fieldnames { $_[0]->{fieldnames} }
sub templatestr {
my $self = shift;
return join " ", @{$self->{template_ary}};
}
1;
package main;
use warnings;
use strict;
my $format = Unpack::Format->new(
spec => [
status => 'n ', # 0
time => 'n ', # 2
date => 'N ', # 4
code => 'a16', # 8 key
msid => 'a10', # 24 key
]
);
my $rec = "\x{00}\x{7B}\x{06}\x{B3}\x{01}\x{32}\x{1A}\x{83}"
.'code_value------msid_value';
my %test_vals;
print "$format\n";
@test_vals{ @$format } = unpack $format, $rec;
foreach (@$format) {
printf " %6s => %s\n",$_, $test_vals{$_};
}
s;;Just-me-not-h-Ni-m-P-Ni-lm-I-ar-O-Ni;;tr?IerONim-?HAcker ?d;print