Глубокое клонирование объекта Moose с атрибутами, такими как ArrayRef [Object] и Set :: Object - PullRequest
6 голосов
/ 21 августа 2010

У меня есть Лось объект:

class My::Game {
  has 'players' => (isa => 'Set::Object', ...)
  has 'action_sequence' => (isa => 'ArrayRef[My::Game::Action]', ...)
}

Теперь я хочу иметь возможность клонировать этот объект с помощью вызова, подобного $game2 = $game->clone; Как глубоко клонировать его, чтобы клонировать объекты в ArrayRef? И что еще хитрее, Set :: Object ?

Я смотрел на MooseX :: Clone , но мне неясно, как применить его к этому делу. Пример кода будет оценен.

Спасибо!

Ответы [ 2 ]

5 голосов
/ 21 августа 2010

Я не использовал здесь ни одной из частей ( MooseX :: Clone , MooseX :: Compile и Set :: Object ), поэтому вот только приблизительный план того, с чего я начну, из моего обзора документов и общих знаний об архитектуре Moose:

  • MooseX :: Clone дает вашему объекту метод clone (), который затем будет вызывать clone () для каждого из ваших атрибутов с чертой 'Clone'.
  • Итак, вам нужно добавить метод clone () для обоих ваших атрибутов ...
  • это будет моя амбициозная надежда , что MooseX :: Clone может обработать встроенные атрибуты arrayrefs , но, поскольку это, вероятно, нет, вы можете расширить эту функцию самостоятельно (т.е. если у 'action_sequence' есть опция traits => ['Array'], то достаточно разумно, чтобы метод clone фактически определялся с помощью handles => { clone => [ 'map', 'clone' ] } - т.е. клонировать атрибут, вызывая clone () для каждого из элементов-членов) - здесь, вероятно, где вы бы отправили свой первый патч
  • Документация Set :: Object предполагает, что вы можете надежно клонировать объекты с помощью Storable :: dclone (что вы должны проверить, и выпустить автора и / или предоставить исправления, если это не правильно)
  • и теперь вам нужно добавить метод clone () к атрибуту Set :: Object, что в документах предлагается вам сделать с MooseX :: Compile (и здесь вам следует обратиться к irc. perl.org #moose и расскажите нам о вашем прогрессе, чтобы мы могли сделать документальный фильм об этом позже):)
2 голосов
/ 25 августа 2010

Оказывается, что простое добавление роли MooseX::Clone в класс обеспечивает метод clone(), который рекурсивно клонирует атрибуты.

  • Для атрибутов hashref / arrayref он копирует структуры.
  • Для скаляров (включая ссылки) он просто делает поверхностную копию ссылки.
  • Если вы добавите traits => ['Clone'] к атрибуту, он будет рекурсивно клонировать атрибут, вызвав clone() для значения атрибута.

Чтобы поддержать клонирование Set::Object, я создал черту CloneByCoercion, подклассифицировав черту Clone, параметризованную с типом, который будет приводиться к / от перед клонированием.

Итак, чтобы использовать его, я написал:

has 'blah' => (isa => 'Set::Object', is => rw,
  traits => ['CloneByCoercion' => {to=>'ArrayRef'}]
);

MooseX::Types::Set::Object обеспечивает приведения к ArrayRef и из него (хотя мне нужно было исправить ошибку в нем: приведение к ArrayRef должно возвращать ссылку, а неlist)

Я также изменил MooseX::Clone, чтобы сохранить хэш, видимый объектами, чтобы он поддерживал клонирование структур связанных объектов с циклическими ссылками.

В конце концов я обойдудля размещения этого материала на CPAN или для отправки исправлений в модули.

...