我有很多级别的大哈希,我想把这个哈希变成一组Moose类。
哈希看起来像这样:
my %hash = (
company => {
id => 1,
name => 'CorpInc',
departments => [
{
id => 1,
name => 'Sales',
employees => [
{
id => 1,
name => 'John Smith',
age => '30',
},
],
},
{
id => 2,
name => 'IT',
employees => [
{
id => 2,
name => 'Lucy Jones',
age => '28',
},
{
id => 3,
name => 'Miguel Cerveza',
age => '25',
},
],
},
],
}
);
穆斯班:
package Company;
use Moose;
has 'id' => (is => 'ro', isa => 'Num');
has 'name' => (is => 'ro', isa => 'Str');
has 'departments' => (is => 'ro', isa => 'ArrayRef[Company::Department]');
1;
package Company::Department;
use Moose;
has 'id' => (is => 'ro', isa => 'Num');
has 'name' => (is => 'ro', isa => 'Str');
has 'employees' => (is => 'ro', isa => 'ArrayRef[Company::Person]');
1;
package Company::Person;
use Moose;
has 'id' => (is => 'ro', isa => 'Num');
has 'first_name' => (is => 'ro', isa => 'Str');
has 'last_name' => (is => 'ro', isa => 'Str');
has 'age' => (is => 'ro', isa => 'Num');
1;
将此哈希转换为公司对象的最佳方法是什么?
到目前为止我考虑过的选项是:
还有其他想法或建议吗?
答案 0 :(得分:2)
您可以使用BUILDARGS处理程序将这些插槽中的未经处理的引用转换为对象。强制可能是最好的,但它需要更多。 (除非这些都来自RDBMS,在这种情况下使用DBIx::Class
)。
#!/usr/bin/env perl
use warnings;
use strict;
package Company;
use Moose;
has 'id' => (is => 'ro', isa => 'Num');
has 'name' => (is => 'ro', isa => 'Str');
has 'departments' => (is => 'ro', isa => 'ArrayRef[Company::Department]');
sub BUILDARGS {
my $self = shift;
my $args = $self->SUPER::BUILDARGS(@_);
@{ $args->{departments} } =
map { eval{ $_->isa('Company::Department') } ? $_ : Company::Department->new($_) }
@{ $args->{departments} };
return $args;
};
package Company::Department;
use Moose;
has 'id' => (is => 'ro', isa => 'Num');
has 'name' => (is => 'ro', isa => 'Str');
has 'employees' => (is => 'ro', isa => 'ArrayRef[Company::Person]');
sub BUILDARGS {
my $self = shift;
my $args = $self->SUPER::BUILDARGS(@_);
@{ $args->{employees} } =
map { eval{ $_->isa('Company::Person') } ? $_ : Company::Person->new($_) }
@{ $args->{employees} };
return $args;
};
package Company::Person;
use Moose;
has 'id' => (is => 'ro', isa => 'Num');
has 'name' => (is => 'ro', isa => 'Str');
has 'age' => (is => 'ro', isa => 'Num');
package main;
my %hash = (
company => {
id => 1,
name => 'CorpInc',
departments => [
{
id => 1,
name => 'Sales',
employees => [
{
id => 1,
name => 'John Smith',
age => '30',
},
],
},
{
id => 2,
name => 'IT',
employees => [
{
id => 2,
name => 'Lucy Jones',
age => '28',
},
{
id => 3,
name => 'Miguel Cerveza',
age => '25',
},
],
},
],
}
);
my $company = Company->new($hash{company});
use Data::Dumper;
print Dumper $company;
答案 1 :(得分:1)
我已经多次使用你的选项2,它对我来说很好。最后一个实例是将JIRA REST API结果膨胀为真实对象。请注意,通过强制,您还可以按id查找现有实例,并仅在不存在时创建。
编辑:以下是一些展示这些强制措施的代码:
package Company::Types;
use Moose::Util::TypeConstraints;
subtype 'Company::Departments', as 'ArrayRef[Company::Department]';
coerce 'Company::Departments', from 'ArrayRef', via {
require Company::Department;
[ map { Company::Department->new($_) } @$_ ]
};
subtype 'Company::Persons', as 'ArrayRef[Company::Person]';
coerce 'Company::Persons', from 'ArrayRef', via {
require Company::Person;
[ map { Company::Person->new($_) } @$_ ]
};
no Moose::Util::TypeConstraints;
并在那些课程中:
use Company::Types;
has 'departments' => (is => 'ro', isa => 'Company::Departments', coerce => 1);
has 'employees' => (is => 'ro', isa => 'Company::Persons', coerce => 1);
然后你可以将整个结构传递给Company
构造函数,并且所有构造都能正常膨胀。