2016-05-13 64 views
1

我似乎无法弄清楚这一点,我不能在网上找到的任何东西。因此,这里是我的代码:“无法调用‘类别’没有包装或对象引用的”在Perl

Type.pm

use constant { 
UNABLE_TO_PING_SWITCH_ERROR => { 
     category => 'Connection Error', 
     template => "Could not ping switch %s in %s seconds.", 
     context => [ qw(switch_ip timeout) ], 
     tt => {template => 'disabled'}, 
     fatal => 1, 
     wiki_page => 'www.error-fix.com/', 
    }, 
}; 

Error.pm 新方法输出的字符串化

# Method for creating error message 
    sub new { 
     my ($class, $error, %args) = @_; 
     # Initialize error with data 
     my $self = $error; 
     # If the error contains context parameters... Insert parameters into string template 
     if(%args) { 
      foreach my $key (@{ $self->{context} }) { 
       # And take the ones we need 
       $self->{args}->{$key} = $args{$key}; 
      } 
      my @template_args = map { $self->{args}->{$_} } @{ $self->{context} }; 
      # map/insert arguments into context hash and insert into string template 
      $self->{message} = sprintf ($self->{template}, @template_args); 
      $self->stringify; 
      } 
      return bless $self, $class; 
     } 
     else { return bless $self, $class; } 
    } 

stringify { 
    my ($self) = @_; 
    return sprintf("%s : %s\nMore info: %s", $self->category, $self->message, $self->wiki_page); 
} 

这显示在格式错误消息是我的错误接收。

# Failed test 'Return the correct message' 
    # at t/67_Error.t line 47. 
    #   got: undef 
    #  expected: 'Could not ping switch 192.192.0.0 in 30 seconds.' 
Can't call method "category" without a package or object reference at Error.pm line 77. 

77行是stringify中的return语句。

如果您需要了解更多信息或代码,让我知道。

尝试溶液(SOF远)

sub new { 
    my ($class, $error, %args) = @_; 
    # Initialize error with data 
    my $self = $error; 
    # If the error contains context parameters... Insert parameters into string template 
     if($self eq 'HASH' && %args) { 
      bless $self, $class; 
      foreach my $key (@{ $self->{context} }) { 
       # bless $self, $class; 
       # And take the ones we need 
       $self->{args}->{$key} = $args{$key}; 
      } 
      my @template_args = map { $self->{args}->{$_} } @{ $self->{context} }; 
      # map/insert arguments into context hash and insert into string template 
      $self->{message} = sprintf ($self->{template}, @template_args); 
      my $output = _stringify($self->category, $self->message, $self->wiki_page); 
      bless $output, $class; 
      return $output; 
      } 
      else { return bless $self, $class; } 
    } 

测试代码:吨/ 67_Error.t

#!/usr/bin/env perl 

use lib ('./t/lib'); 
use strict; 
no strict 'refs'; 
use warnings; 

use ASC::Builder::Error; 
use ASC::Builder::Error::Type; 
use ASC::Builder::Error::Type 'code'; 
use Test::More; 
use Test::Exception; 
use LWP::Simple 'head'; # Used to test if wiki link is giving a response 

subtest 'Functionality of Error' => sub { 

    my $example_error = { 
     category => 'Connection Error', 
     template => 'Could not ping switch %s in %s seconds.', 
     context => [ qw(switch_ip timeout) ], 
     tt => {template => 'disabled'}, 
     fatal => 1, 
     wiki_page => 'http://www.error-fix.com', 
    }; 
    # Correct case 
    { 
     my $error = ASC::Builder::Error->new($example_error, timeout => 30, switch_ip => '192.192.0.0'); 

     isa_ok ($error, 'ASC::Builder::Error'); 

     can_ok ($error, 'category'); 
     is ($error->category(), 'Connection Error', 'Return the correct category'); 

     can_ok ($error, 'template'); 
     is ($error->template(), 'Could not ping switch %s in %s seconds.', 'Return the correct category'); 

     can_ok ($error, 'tt'); 
     is ($error->tt(), 'disabled', 'Return the correct tt template'); 

     can_ok ($error, 'context'); 
     is_deeply($error->context(), ['switch_ip', 'timeout'], 'Return the correct context params'); 

     can_ok ($error, 'is_fatal'); 
     ok($error->is_fatal(), 'Return the correct value'); 

     can_ok ($error, 'message'); 
     is ($error->message(), 'Could not ping switch 192.192.0.0 in 30 seconds.', 'Return the correct message'); 
     can_ok ($error, 'stringify'); 
     is ($error->stringify(), "Connection Error : Could not ping switch 192.192.0.0 in 30 seconds.\nMore info: http://www.error-fix.com", 'stringify creates the correct message'); 

}; 

    # Too many arguments (this is okay) 
    lives_ok(sub { ASC::Builder::Error->new($example_error, timeout => 1, switch_ip => 2, extra => 3) }, 'Creating with too many arguments lives. (allows for additional context   string to be added in the code)'); 
    }; 

    subtest 'Correctness of Type.pm' => sub { 

# These test cases contain all the errors from Type.pm 
    my @test_cases = (
     { 
      name => 'UNABLE_TO_PING_SWITCH_ERROR', 
      args => { 
       switch_ip => '192.192.0.0', 
       timeout => 30, 
      }, 
      message => 'Could not ping switch 192.192.0.0 in 30 seconds.', 
     }, 
    ); 


    foreach my $t (@test_cases) { 
     subtest $t->{name} => sub { 
      no strict 'refs'; # Because we need to use variable to get to a constant 
      ASC::Builder::Error::Type->import($t->{name}); 

      # Create the Error object from the test data 
      # Will also fail if the name was not exported by Type.pm 
      my $error; 
      lives_ok(sub { $error = ASC::Builder::Error->new(&{ $t->{name} },%{ $t->{args} }) }, 'Error can be created'); 

      # See if it has the right values 
      is ($error->message, $t->{message}, 'Error message is correct'); 

      # Using LWP::Simple to check if the wiki page link is not broken 
      #ok head($error->wiki_page); #CANT'T GET THIS TEST TO WORK 

     } 
    } 
}; 
done_testing; 

UPDATE:消息方法:

这仅仅是一个吸气剂。

sub message { 
     return shift->{message}; 
} 
+1

为什么你叫'stringify'构造函数里面? – ThisSuitIsBlackNot

+1

请显示触发此问题的实际测试代码。 – stevieb

+0

确定会添加测试代码。 –

回答

1

总之:关键字sub是在前面stringify缺席,和unblessed $self呼叫的方法。

(1)缺乏sub关键字的触发行为抛出了诊断。 stringify { ... }简单地称为类方法,正式通过hashref。当然,hashref并没有什么是正确的,我们得到了早期的错误,并将其识别为伪造。从perldiag

Can't call method "%s" without a package or object reference
(F) You used the syntax of a method call, but the slot filled by the object reference or package name contains an expression that returns a defined value which is neither an object reference nor a package name. Something like this will reproduce the error:

$BADREF = 42; 
process $BADREF 1,2,3; 
$BADREF->process(1,2,3); 

呼叫$self->stringify无关,用它做,并且永远不会执行,因为这是一个致命的错误。 (确切的错误信息是在V5.10对我来说不同)

(2)当sub被放在它的位置,我们得到的问题:$self调用是bless -ed之前的方法。这在ThisSuitIsBlackNot的评论中也被观察到。现在有没有必要,为什么连作品的炒作,但我们得到了预期的错误

 
Can't call method "stringify" on unblessed reference at ErrorPack.pm ... 

(3)当我们第一次bless调用它的方法之前,hashref,我们得到

 
Can't locate object method "category" via package "ErrorPack" at ErrorPack.pm ... 

由于预计,因为$self现在是一个对象,并且确实没有方法“类别”。这可以通过改变printf中的调用来解决,以便减少hashref,而不是调用方法(通过添加curlies)。在bipll的答案中也注明。

我不知道这些变化是如何发挥随着海报的意图,但与所有的

文件ErrorPack.pm

package ErrorPack; 

use warnings; 
use strict; 

# Method for creating error message 
sub new { 
    my ($class, $error, %args) = @_; 
    # Initialize error with data 
    my $self = $error; 
    bless $self, $class; 
    # If the error contains context parameters... [...] 
    if (%args) { 
     foreach my $key (@{ $self->{context} }) { 
      # And take the ones we need 
      $self->{args}->{$key} = $args{$key}; 
     } 
     my @template_args = map { $self->{args}->{$_} } @{ $self->{context} }; 
     # map/insert arguments into context hash and insert into string template 
     $self->{message} = sprintf ($self->{template}, @template_args); 
     $self->stringify; 
    } 
    return $self; 
} 

sub stringify { 
    my ($self) = @_; 
    return sprintf("%s : %s\nMore info: %s", $self->{category}, 
     $self->{message}, $self->{wiki_page}); 
} 
sub prn { print "$_[0]->{category}\n" } 
1; 

如果有任何理由不使$self%args处理之前的对象,在致电stringify 然后return $self;之前发出bless $self, $class;

脚本,主要::

use warnings; 
use strict; 

use ErrorPack; 

# Taken from testing code that is now posted 
my $err = { 
    category => 'Connection Error', 
    template => "Could not ping switch %s in %s seconds.", 
    context => [ qw(switch_ip timeout) ], 
    tt => {template => 'disabled'}, 
    fatal => 1, 
    wiki_page => 'www.error-fix.com/', 
}; 

my $eobj = ErrorPack->new($err, timeout => 30, switch_ip => '192.192.0.0'); 
$eobj->prn(); 

此打印一行Connection Error,将$eobj可直接用于查询键等

+0

是否有可能拥有它,以便新方法(何时调用)将打印出值而不必显式调用prn()? –

+0

这是stringify的拼写错误。对不起 –

+0

@PaulRussell是的,你可以随意打包。所以你可以将打印语句添加到'new',并且当'new'被调用时它们将运行,所以无论何时创建一个对象。请记住,在'bless'语句执行之前(在'new'中)'$ self'还不是一个对象,所以你不能调用它。你可以通过去除它的关键字来从中提取数据。 (我添加了一个单独的玩具方法来证明它的全部工作,虽然你可能希望实际上有一个方法可以打印一个对象的所有数据,但是)。 – zdim

0
return sprintf("%s : %s\nMore info: %s", $self->category, $self->message, $self->wiki_page); 

这里的代码看起来像你调用方法称为category,在$selfmessagewiki_page。如果它们实际上是散列键,则应该将它们放在大括号中。

+1

他们可能应该作为构造函数以外的方法调用,以保持封装(尽管不清楚OP是否实际实现了任何方法)。 OP的错误发生是因为'$ self'在调用'$ self-> stringify'时是一个不成对的hashref,而不是一个对象。 – ThisSuitIsBlackNot

+0

@ThisSuitIsBlack那么它是如何设法打电话的呢? – hobbs

+0

@ThisSuitIsBlackNot,最顶级代码片段的常量哈希包含'category'和'wiki_page'作为键,所以我认为... – bipll

相关问题