Использование BUILDARGS для замены класса в роли - PullRequest
0 голосов
/ 19 сентября 2018

Я использую Perl Moose Role (Import::Git::Role) в качестве абстрактного базового класса, чтобы разделить общее поведение между классом, реальной реализацией функциональности (Import::Git) и классом, который вместо этого выполняет некоторое ведение журнала (Import::Git::dryrun).

Я бы хотел, чтобы класс dryrun был прозрачным.Я хочу создать объект, подобный этому:

   my $git = Import::Git->new( dryrun => $dryrun );

Переменная dryrun может быть 0 или 1. Если это 1, я хотел бы вместо этого создать объект Import::Git::dryrun, в основном заменив Import::Gitвозразить с этим.Это было задумано, потому что они разделяют все методы через роль.

Я пытался обменять объект во время метода BUILDARGS следующим образом:

around BUILDARGS => sub {                                                                                                                                                                                                                                                           
     my $orig  = shift;
     my $class = shift;

     my %args = ( @_ == 1 ? %{ $_[ 0 ] } : @_ );

     if ( !%args || $args{ 'dryrun' } != 1 ) {
         return $class->$orig( @_ );
     }
     else {
         return Import::Git::dryrun->$orig( @_ );
    }
};

, но это не позволяет достичь того, что я пытаюсьдля этого он создает старый класс:

  DB<1> x Import::Git->new( dryrun => 1 )
0  Import::Git=HASH(0x2fd9210)
   'dryrun' => 1
  DB<2> x Import::Git->new()
0  Import::Git=HASH(0x301dbb8)
   'dryrun' => 0
  DB<3> 

Я подумал, что, возможно, мне придется вызвать новый метод метода dryrun, поэтому я произвел следующий обмен:

   # change this:
   return Import::Git::dryrun->$orig( @_ );
   # to this
   return Import::Git::dryrun->new( @_ ); 

Но возвращается BUILDARGS did not return a HASH reference.

Чего мне не хватает?

Ответы [ 2 ]

0 голосов
/ 19 сентября 2018

Наличие конструктора, отличного от запрошенного класса, - icky.Я бы не стал подходить к вам, даже если бы это сработало.Я бы использовал

sub factory {
   my ($class, %opts) = @_;
   return $opt{dryrun} ? $class.'::dryrun' : $class;
}

Import::Git->factory( dryrun => $dryrun )->new( ... )

или

sub instantiate {
   my ($class, %opts) = @_;
   return ( delete($opt{dryrun}) ? $class.'::dryrun' : $class )->new(%opts);
}

Import::Git->instantiate( dryrun => $dryrun, ... )
0 голосов
/ 19 сентября 2018

BUILDARGS используется для управления списком аргументов, который вы передаете конструктору объектов перед созданием объекта, поэтому не будет влиять на то, что возвращает новый.Вместо around BUILDARGS вы можете попробовать around new, тогда вы можете заменить объект, возвращенный новым, вашим объектом пробного запуска.

...