Привет, ребята. Недавно я столкнулся с проблемой, которую я очень ценю. Я опубликовал аналогичный вопрос перед Рождеством в PerlMonks с некоторыми отзывами, чтобы переключиться с MooseX :: Declare ([http://www.perlmonks.org/?node_id=877703][1]). Я теперь переключил код на Vanilla Moose с MooseX :: Types и MooseX :: Params :: Validate). Тем не менее, та же ошибка происходит в том же месте. Неудивительно, поскольку она, похоже, связана с MooseX :: Types.
Я получаю следующую ошибку (попытался выделить это для удобства чтения)
и дно стека усекается):
plxc16479> tmp10.pl
Argument cannot be 'name' at /nfs/pdx/disks/nehalem.pde.077/perl/lib64/site_perl/MooseX/Types/TypeDecorator.pm line 88
MooseX::Types::TypeDecorator::new('MooseX::Types::TypeDecorator=HASH(0x1620c58)', 'name', 'g1145114N5582201_16161616a2x_FU02xxT_2bxc2e3_6x0xxxp0fx0xxx0x...', 'mask_data', '', 'tags', 0) called at /nfs/pdx/disks/nehalem.pde.077/projects/lib/Program-Plist-Pl/lib/Program/Plist/Pl.pm line 61
Program::Plist::Pl::_create_pattern_obj(undef, 'name', 'g1145114N5582201_16161616a2x_FU02xxT_2bxc2e3_6x0xxxp0fx0xxx0x...', 'mask_data', '', 'tag_data', '') called at /nfs/pdx/disks/nehalem.pde.077/projects/lib/Program-Plist-Pl/lib/Program/Plist/Pl.pm line 77
Program::Plist::Pl::BUILD('Program::Plist::Pl=HASH(0x162d6c0)', 'HASH(0x162d648)') called at generated method (unknown origin) line 101
Program::Plist::Pl::new('Program::Plist::Pl', 'name', 'bist_hfmmin_16161616_list', 'parents', 'HASH(0xccf040)', 'fh', 'GLOB(0xccc928)', 'external_pl_code', 'CODE(0x14910b0)', ...) called at /nfs/pdx/disks/nehalem.pde.077/projects/lib/Program-Roles-PlHandler/lib/Program/Roles/PlHandler.pm line 52
Program::Roles::PlHandler::_create_global_pl_obj(undef, 'name', 'bist_hfmmin_16161616_list', 'parents', 'HASH(0xccf040)', 'fh', 'GLOB(0xccc928)') called at /nfs/pdx/disks/nehalem.pde.077/projects/lib/Program-Plist-Pl/lib/Program/Plist/Pl.pm line 77
Program::Plist::Pl::BUILD('Program::Plist::Pl=HASH(0xccd300)', 'HASH(0xccc628)') called at generated method (unknown origin) line 101
Program::Plist::Pl::new('Program::Plist::Pl', 'name', 'bist_list', 'parents', 'HASH(0xccce80)', 'fh', 'GLOB(0xccc928)', 'external_pl_code', 'CODE(0x14910b0)', ...) called at /nfs/pdx/disks/nehalem.pde.077/projects/lib/Program-Roles-PlHandler/lib/Program/Roles/PlHandler.pm line 52
Проблема в том, что мне кажется, что это главный вызов TypeDecorator :: new. Кажется, что конструктор TypeDecorator ожидает два аргумента: аргумент class / self и ссылку на объект TypeDecorator или TypeConstraint. Вместо этого он каким-то образом получает аргументы от моего вызова объекта create pattern. Я проверил, что аргументы, входящие в функцию _create_pattern_obj, являются правильными и что аргументы, входящие в вызов Pattern-> new, также являются правильными (подтверждаются аргументами, отслеживаемыми стеком). Функция _create_pattern_obj выглядит следующим образом:
sub _create_pattern_obj {
my ($self, $name, $mask_data, $tag_data) = validated_list(\@_,
name => {isa => Str},
mask_data => {isa => Str, optional => 1},
tag_data => {isa => Str, optional => 1});
$mask_data = '' if !defined $mask_data;
my $tags = defined $tag_data ? map {$_ => 1} split(',', $tag_data) : {};
my $pattern_obj = Program::Plist::Pl::Pattern->new(name => $name,
mask_data => $mask_data,
tags => $tags);
$self->_add_pattern($pattern_obj);
}
Функция умирает при вызове Program :: Plist :: Pl :: Pattern->, который является строкой 61
в файле Pl.pm, указанном в стеке вызовов, из которого, как утверждается, поступил вызов TypeDecorator :: new.
Класс Pattern:
package Program::Plist::Pl::Pattern;
use 5.012002;
our $VERSION = sprintf "2.%03d", q($Revision: 473 $) =~ /: (\d+)/;
use Moose;
use namespace::autoclean;
use MooseX::Types::Moose qw(Str Num Int HashRef);
use MooseX::Params::Validate;
has 'name' => (isa => Str,
is => 'ro',
required => 1);
has 'tuple' => (isa => Int,
is => 'ro');
has 'tid' => (isa => Int,
is => 'ro');
has 'weight' => (isa => Num,
is => 'ro');
has 'tags' => (isa => HashRef[Str],
is => 'ro',
default => sub {{}});
has 'mask_data' => (isa => Str,
is => 'rw',
default => '',
writer => '_set_mask_data');
sub has_tag {
my ($self, $tag) = (shift,
pos_validated_list(\@_, {isa => Str}));
exists $self->{tags}->{$tag} ? return 1 : return 0;
}
sub _add_tag {
my ($self, $tag) = (shift,
pos_validated_list(\@_, {isa => Str}));
$self->{tags}->{$tag} = 1;
}
sub BUILDARGS {
print STDERR 'CALLED '.__PACKAGE__."BUILDARGS\n";
print STDERR 'ARGUMENTS:'.join(',', @_)."\n";
}
sub BUILD {
my ($self) = @_;
print STDERR 'CALLED '.__PACKAGE__."::BUILD\n";
}
__PACKAGE__->meta->make_immutable;
1;
Каким-то образом, судя по аргументам в стеке вызовов, мои аргументы для вызова Pattern-> new в конечном итоге передаются вызову TypeDecorator :: new, и он их душит. Я убедился, что хороший вызов этой подпрограммы (из более ранней трассировки стека) выглядит следующим образом (обратите внимание на два аргумента):
DB <1> T
$ = MooseX :: Types :: TypeDecorator :: new ('MooseX :: Types :: TypeDecorator', ref (Moose :: Meta :: TypeConstraint)), вызываемый из файла `/nfs/pdx/disks/nehalem.pde.077. /perl/lib64/site_perl/MooseX/Types.pm 'строка 464
Проблема в том, что я не могу понять, как отлаживать происходящее. При пошаговом выполнении кода выполнение переходит непосредственно из вызова Pattern-> new в код TypeDecorator. Это происходит перед выполнением любого кода моего класса. Я знаю, что Moose создает для меня новый метод, но я не могу понять, как отлаживать код, на который я не могу смотреть.
Я просмотрел документацию по Moose, но это все о том, как ее использовать, а не о том, что происходит под капотом. Я прочитал документацию по Class :: MOP, но мне неясно, где именно и когда создается этот код. Несмотря на то, что я многому научился из всех моих исследований, ни одно из них не помогло мне напрямую с моей проблемой:)
Прежде всего, любые идеи относительно того, что происходит, будут оценены. Во-вторых, как мне отладить эту проблему? Все мои обычные инструменты отладки подвели меня! Выполнение переходит прямо из моего нового вызова в код проблемы, и я не могу проследить, откуда фактически передаются аргументы TypeDecorator :: new. И, наконец, есть ли хорошие отзывы о том, как Moose делает то, что делает? Или Класс :: MOP?
Редактировать - вот мои определения типов. Я мог бы добавить, что это мой первый набег на Moose, так что если вы видите, что я делаю что-то странное, не стесняйтесь указывать на это.
package Program::Types;
use 5.012002;
use strict;
use warnings;
our $VERSION = sprintf "2.%03d", q($Revision: 473 $) =~ /: (\d+)/;
# predeclare types
use MooseX::Types
-declare => [qw(NonemptyStr FilePath DirectoryPath FilePathThatExists DirectoryPathThatExists
TwoDigNum Pl LocalPl Pattern Program_Env Program_Whichload Program_Tpl
Program_Plist Program_Bmfc Program_Tpl_Test Program_Tpl_Flow
Program_Tpl_Flow_Item Program_Tpl_Flow_Item_Result Word)];
# import some MooseX builtin types that will be built on
use MooseX::Types::Moose qw(Str Int Object);
# types base on some objects that I use
class_type Pl, {class => 'Program::Plist::Pl'};
class_type LocalPl, {class => 'Program::Plist::LocalPl'};
class_type Pattern, {class => 'Program::Plist::Pl::Pattern'};
class_type Program_Env, {class => 'Program::Env'};
class_type Program_Whichload, {class => 'Program::Whichload'};
class_type Program_Tpl, {class => 'Program::Tpl'};
class_type Program_Tpl_Test, {class => 'Program::Tpl::Test'};
class_type Program_Tpl_Flow, {class => 'Program::Tpl::Flow'};
class_type Program_Tpl_Flow_Item, {class => 'Program::Tpl::Flow::Item'};
class_type Program_Tpl_Flow_Item_Result, {class => 'Program::Tpl::Flow::Item::Result'};
class_type Program_Plist, {class => 'Program::Plist'};
class_type Program_Bmfc, {class => 'Program::Bmfc'};
subtype Word,
as Str,
where {$_ =~ /^\w*$/};
coerce Word,
from Str,
via {$_};
subtype NonemptyStr,
as Str,
where {$_ ne ''};
coerce NonemptyStr,
from Str,
via {$_};
subtype TwoDigNum,
as Int,
where {$_ =~ /^\d\d\z/},
message {'TwoDigNum must be made of two digits.'};
coerce TwoDigNum,
from Int,
via {$_};
subtype FilePath,
as Str,
where {!($_ =~ /\0/)},
message {'FilePath cannot contain a null character'};
coerce FilePath,
from Str,
via {$_};
subtype DirectoryPath,
as Str,
where {!($_ =~ /\0/)},
message {'DirectoryPath cannot contain a null character'};
coerce DirectoryPath,
from Str,
via {$_};
subtype FilePathThatExists,
as Str,
where {(!($_ =~ /\0/) and -e $_)},
message {'FilePathThatExists must reference a path to a valid existing file.'.
"Path ($_)"};
coerce FilePathThatExists,
from Str,
via {$_};
coerce FilePathThatExists,
from FilePath,
via {$_};
subtype DirectoryPathThatExists,
as FilePath,
where {(!($_ =~ /\0/) and -d $_)},
message {'DirectoryPathThatExists must reference a path to a valid existing '.
"directory. Path ($_)"};
coerce DirectoryPathThatExists,
from Str,
via {$_};
coerce DirectoryPathThatExists,
from DirectoryPath,
via {$_};
1;
Edit2 - удалено из-за очевидной ошибки оператора :) Обратите внимание, что я использую BUILDARGS в классе Pattern без возврата списка аргументов. Я удалил это в текущем коде без изменений в ошибке.
Phaylon, вот программа :: Plist :: Pl класс.
package Program::Plist::Pl;
use 5.012002;
our $VERSION = sprintf "2.%03d", q($Revision: 473 $) =~ /: (\d+)/;
use Moose;
use namespace::autoclean;
use Program::Plist::Pl::Pattern;
use Program::Types qw(Pl LocalPl TwoDigNum Pattern);
use Program::Utils qw(rchomp);
use MooseX::Types::Moose qw(HashRef GlobRef Str);
use MooseX::Params::Validate;
with 'Program::Roles::PlHandler';
has 'name' => (isa => Str,
is => 'ro',
required => 1);
has 'parents' => (isa => HashRef[Pl|LocalPl],
is => 'ro',
required => 1);
has 'children' => (isa => HashRef[Pl|LocalPl],
is => 'ro');
has 'prefixes' => (isa => HashRef[TwoDigNum],
is => 'ro',
default => sub{{}});
has 'patterns' => (isa => HashRef[Pattern],
is => 'ro',
default => sub{{}});
sub _add_child {
my ($self, $obj) = (shift,
pos_validated_list(\@_, {isa => Pl|LocalPl}));
$self->{children}->{$obj->name} = $obj;
}
sub _add_pattern {
my ($self, $obj) = (shift,
pos_validated_list(\@_, {isa => Pattern}));
$self->{patterns}->{$obj->name} = $obj;
}
sub _create_pattern_obj {
$DB::single = 1;
my ($self, $name, $mask_data, $tag_data) = validated_list(\@_,
name => {isa => Str},
mask_data => {isa => Str, optional => 1},
tag_data => {isa => Str, optional => 1});
$mask_data = '' if !defined $mask_data;
my $tags = defined $tag_data ? map {$_ => 1} split(',', $tag_data) : {};
$DB::single = 1;
my $pattern_obj = Program::Plist::Pl::Pattern->new(name => $name,
mask_data => $mask_data,
tags => $tags);
$self->_add_pattern($pattern_obj);
}
sub BUILD {
my ($self, $fh) = (shift,
pos_validated_list([$_[0]->{fh}], {isa => GlobRef}));
while (<$fh>) {
# skip empty or commented lines
rchomp;
next if ((/^\s*#/) or (/^\s*$/));
# handle global plist declarations
if (my @m = /^\s*GlobalPList\s+(\w+)/) {
# creating new object and adding it to our data print STDERR
# "SELF($self)\n".join("\n",sort keys
# %Program::Plist::Pl::)."\n";
$self->_create_global_pl_obj(name => $m[0],
parents => {%{$self->parents},
$self->name => $self},
fh => $fh);
}
# handle local referenced plist declarations
elsif (@m = /^\s*PList\s+(\w+):(\w+)/) {
$self->_create_local_pl_obj(file => $m[0],
name => $m[1]);
}
# handling pattern lines
elsif (@m = /^\s*Pat\s+(\w+)\s*(\[.*\])?\s*;\s*(#([\w,])#)?\s*$/) {
$self->_create_pattern_obj(name => $m[0],
mask_data => do {defined $m[1] ? $m[1] : ''},
tag_data => do {defined $m[2] ? $m[2] : ''});
}
# handling our patlist closure
elsif (/^\s*\}/) {
last;
}
}
# need to populate our hash of child plists
for (@{$self->data}) {
if (($_->isa('Pl')) or ($_->isa('LocalPl'))) {
$self->_add_child($_);
}
}
}
__PACKAGE__->meta->make_immutable;
1;