3

私は多くのレベルの深さの大きなハッシュを持っており、このハッシュを一連の 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',
                    },
                ],
            },
        ],
    }
);

Moose クラス:

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;

このハッシュを Company オブジェクトに変換する最良の方法は何ですか?

これまでに検討したオプションは次のとおりです。

  1. %hash を手動でループし、最も深い「クラス」(例: Person) を見つけ、最初にこれらを作成してから、新しく作成されたより高いレベルのクラス (Department) にこれらを手動で追加します。
  2. 各クラスにある種の強制機能を追加すると、Company->new(%hash) のようなことができ、各クラスに独自の「サブクラス」を (強制によって) 作成させることができます。
  3. %hash を MooseX::Storage がシリアル化するものと同様の構造に変換し、MooseX::Storage を使用してすべてをインスタンス化します...

他のアイデアや提案はありますか?

4

2 に答える 2

2

これらのスロット内の unbless 参照をオブジェクトに変換する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;
于 2012-09-18T21:05:23.107 に答える
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、すべてが適切に膨張します。

于 2012-09-19T17:48:40.680 に答える