views:

164

answers:

3

I'm gradually Moose-ifying some code that reads lines from a pipe delimited, splits each and assigns adds them to a hash using a hash slice.

I've turned the hash into a Moose class but now I have no idea how to quickly assign the fields from the file to the attributes of the class (if at all).

I know I can quite easily just do:

my $line = get_line_from_file;
my @fields = split /\|/, $line;
my $record = My::Record->new;
$record->attr1($fields[0]);
...

but I was hoping for a quick one liner to assign all the attributes in one go, somewhat akin to:

my $line = get_line_from_file;
my %records;
@records{@field_names} = split /\|/, $line;

I've read about coercion but from what I can tell it's not what I'm after.

Is it possible?

Thanks

+6  A: 

I think you're on the right track with the hash slice approach. I'd do something like:

my %fields;
@fields{@field_names} = split m{\|}, $line;
my $record = My::Record->new( %fields );

You might be able to come up with a gnarly map solution to achieve the same thing, but I'd err on the side of readability here.

friedo
If 2 of the attributes are arrays (semi-colon delimited in the file) is that when coerce can be used?
Sparkles
Yes, you can use coercion in that instance. You would coerce a `Str` to an `Array` using a coercion function like `sub { return [ split /;/, $_[0] }`
friedo
+2  A: 

If the object is not constructed yet, you can simply pass all the keys and values into the constructor:

my $line = get_line_from_file;
my %records;
@records{@field_names} = split /\|/, $line;
my $object = My::Record->new(%records);

or if the object is already created and you want to add some new fields:

my $line = get_line_from_file;
my %records;
@records{@field_names} = split /\|/, $line;
while (my ($key, $value) = each(%records)
{
    $object->$key($value);

    # or if you use different names for the setters than the "default":
    $object->set_value($key, $value);
}
Ether
+11  A: 

Pass the attributes to the constructor using zip from the List::MoreUtils module:

use List::MoreUtils qw/ zip /;

my $object = My::Record->new(
  zip @field_names,
      @{[ split /\|/, get_line_from_file ]}
);
Greg Bacon
+1 for `zip`, very nice.
friedo