4

たとえば、JSON文字列があります

use JSON::XS qw(decode_json);
say Dumper( decode_json($json) );

生成されます:

$VAR1 = {
    'Fname' => 'SomeFname',
    'Lname' => 'SomeLname',
    'Addr' => {
          'Street => 'Somestreet',
          'Zip' => '00000',
    },
};

次のように、JSON 文字列 (または perl 構造) を Perl/Moose オブジェクトに「変換」する簡単な方法を探しています。

 package My;
 use Moose;
 has 'Fname' => (is => 'rw', isa => 'Str');
 has 'Lname' => (is => 'rw', isa => 'Str');
 has 'Addr' =>  (is => 'rw', isa => 'My::Addr');

 package My::Addr;
 use Moose;
 has 'Street' => (is => 'rw', isa => 'Str');
 has 'Zip' => (is => 'rw', isa => 'Str');

この問題には次の 2 つの部分があります。

  1. JSON 文字列に基づいて Moose クラス階層を定義する (1 回)
  2. JSON からの実際の値を使用してオブジェクト インスタンスを初期化する (JSON ごとに)

私はムースにあまり熟練していないので、この特定の問題について何を学ぶべきかについていくつかのリンクが必要です。

(Moose は大きいので、CPAN ですべてを読むことは確かに役に立ちますが、最初は多すぎます。したがって、上記のように、現実世界の問題を段階的に学習することを探しています)。

主な質問は次のとおりです。

  • データ構造から Moose クラス定義 (perl ソース) を生成することは可能ですか? CPANモジュールのようなものはありますか?
  • クラス階層を取得した場合 (たとえば、ここにヘルパーがない場合は手動で記述できます)、JSON からインスタンスを作成 (初期化) する最も簡単な方法は何ですか?
4

1 に答える 1

5

データ構造から Moose クラス定義 (perl ソース) を生成することは可能ですか? CPANモジュールのようなものはありますか?

はい。ただし、それをどのように行うかは、何を達成したいかによって大きく異なります。最も簡単なのは、JSON に基づいてメモリ内に属性を構築することです。たとえば、次のような JSON ファイルから実行時にメタクラス オブジェクトをインスタンス化できます。

sub infer_class_from_hash {
    my ($input) = @_;

    # Makes for ugly class names, but does the job
    my $meta = Moose::Meta::Class->create_anon_class;

    for my $key (keys %$input) {
        my $value = $input->{$key};

        my $type;
        my $coerce = 0;

        # Handle nested objects in the JSON as Moose objects
        if (ref $value eq 'HASH') {
            my $inner_meta = infer_class_from_hash($value);
            $type = $meta->name;

            # We provide an automatic HASH -> Class coercion
            $coerce = 1;
        }

        # Assume arrays are always of scalars, could be extended to handle objects
        elsif (ref $value eq 'ARRAY') {
            $type = 'ArrayRef',
        }

        # Assume anything else is string-ish
        else {
            $type = 'Str',
        }

        $meta->add_attribute($key =>
            is => 'rw',
            isa => $type,
            coerce => $coerce,
        );
    }

    # Create a coercion that makes instantiating from the JSON tree dead simple
    use Moose::Util::TypeConstraints;
    coerce $meta->name => from 'HashRef' => via { $meta->name->new($_) };
    no Moose::Util::TypeConstraints;

    return $meta;
}

それはすべて、あなたができることにはなりません。ロールを適用したり、カスタムの基本クラスを追加したり、メソッドを追加したりできます。ただし、これが Moose クラスをオンザフライで構築するための基本です。

実際の Moose クラスをファイルとして出力し、一度ビルドして後でロードできるコード ジェネレーターが必要な場合は、好きなことをしてください。上記と同様に動作するプログラムを作成するだけ.pmですが、自動生成された Moose クラス定義を含む一連のファイルを出力します。

クラス階層を取得した場合 (たとえば、ここにヘルパーがない場合は手動で記述できます)、JSON からインスタンスを作成 (初期化) する最も簡単な方法は何ですか?

use JSON qw( from_json );
my $hash = from_json("...");
my $meta = infer_class_from_hash($hash);

my $obj = $meta->name->new($hash);

ここで重要なのは、Moose 型強制を使用して、読み込まれた JSON オブジェクトを Moose クラス インスタンスに自動的に変換する方法です。複数のシリアル化スキームがある場合、または他の方法で型制約を使用する場合は、JSON 入力でネストされたオブジェクトのケースを処理する/メソッドをcreate_anon_class提供するこれらすべての基本クラスを ( の呼び出しで)セットアップできます。 .to_jsonfrom_json

于 2012-09-03T20:55:22.007 に答える