如何在一个漫长的过程中调整对象的渲染? [英] How can I adjust the rendering of objects in a longmess?

查看:117
本文介绍了如何在一个漫长的过程中调整对象的渲染?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在慢慢地将我们的大型Perl应用程序重构为面向对象的界面,特别是数据模型。令人讨厌的部分是堆栈跟踪变得不那么有用。给出一个制造的例子:之前。

We're slowly refactoring our large Perl application towards object-oriented interfaces, especially for data models. The annoying part is that stack traces get less useful. To give a fabricated example: Before.

sub send_message {
    my ($user_id, $message) = @_;
    ...
    Carp::confess('test');
}

# output:
test at example.pm line 23
    foo('42', 'Hello World') called at example.pl line 5

之后。

sub send_message {
    my ($user, $message) = @_;
    ...
    Carp::confess('test');
}

# output:
test at example.pm line 23
    foo('MyApp::Model::User=HASH(0x2c94f68)', 'Hello World') called at example.pl line 5

所以现在我看不到哪个用户被传递到 foo(),我只看到类名(已经记录下来)和某个对象的一些内存地址。

So now I cannot see which user was passed to foo(), I only see the class name (which is already documented) and some memory address of an object.

我试图在模型类上使用overload.pm安装一个stringification操作符:

I tried to install a stringification operator on the model class using overload.pm:

use overload ( '""' => \&stringify );

sub stringify {
    my ($self) = @_;
    return sprintf '%s[id=%d]', ref($self), $self->id;
}

但这并不影响长处。我想要的是这样的:

But this does not affect the longmess. What I would like is something like this:

test at example.pm line 23
    foo('MyApp::Model::User[id=42]', 'Hello World') called at example.pl line 5

也就是说,应该使用对象的 stringify()方法显示 foo()的第一个参数。如何才能实现?

That is, the first parameter to foo() should be displayed using the object's stringify() method. How can I achieve that?

推荐答案

问题出在 Carp.pm

sub format_arg {
    my $arg = shift;
    if ( ref($arg) ) {
        $arg = defined($overload::VERSION) ? overload::StrVal($arg) : "$arg";
    }
    ...
}

一个参数可能是一个重载的对象,那么任何使用 StrVal 帮助器,这会强制执行默认的字符串化。

That is, when an argument could be an overloaded object, then any stringification overloading is circumvented with the StrVal helper, which forces default stringification.

不幸的是,没有直接的方法。我们可以做的只是将猴子补丁到code> Carp :: format_arg sub,例如

Unfortunately, there is no straightforward way around that. All we can do is monkey-patch the Carp::format_arg sub, e.g.

BEGIN {
  use overload ();
  use Carp ();
  no warnings 'redefine';
  my $orig = \&Carp::format_arg;

  *Carp::format_arg = sub {
    my ($arg) = @_;
    if (ref $arg and my $stringify = overload::Method($arg, '""')) {
      $_[0] = $stringify->($arg);
    }
    goto &$orig;
  };
}

就是这样,这是不合适的,应该被写成一个pragma:

As it is, this is inelegant, and should be put into a pragma:

文件鲤鱼/ string_overloading.pm

package Carp::string_overloading;

use strict; use warnings;

use overload ();
use Carp ();

# remember the original format_arg method
my $orig = \&Carp::format_arg;
# This package is internal to Perl's warning system.
$Carp::CarpInternal{ __PACKAGE__() }++;

{
    no warnings 'redefine';
    *Carp::format_arg = sub {
        my ($arg) = @_;
        if (    ref($arg)
            and in_effect(1 + Carp::long_error_loc)
            and my $stringify = overload::Method($arg, '""')
        ) {
            $_[0] = $stringify->($arg);
        }
        goto &$orig;
    };
}

sub import   { $^H{__PACKAGE__ . "/in_effect"} = 1 }

sub unimport { $^H{__PACKAGE__ . "/in_effect"} = 0 }

sub in_effect {
    my $level = shift // 1;
    return (caller $level)[10]{__PACKAGE__ . "/in_effect"};
}

1;

然后代码

use strict; use warnings;

package Foo {
    use Carp ();

    use overload '""' => sub {
        my $self = shift;
        return sprintf '%s[%s]', ref $self, join ", ", @$self;
    };

    use Carp::string_overloading;
    sub foo { Carp::confess "as requested" }

    no Carp::string_overloading;
    sub bar { Carp::confess "as requested" }
}

my $foo = bless [1..3] => 'Foo';

eval { $foo->foo("foo") };
print $@;
eval { $foo->bar("bar") };
print $@;

输出:

as requested at test.pl line 12.
        Foo::foo('Foo[1, 2, 3]', 'foo') called at test.pl line 20
        eval {...} called at test.pl line 20
as requested at test.pl line 15.
        Foo::bar('Foo=ARRAY(0x85468ec)', 'bar') called at test.pl line 22
        eval {...} called at test.pl line 22

这篇关于如何在一个漫长的过程中调整对象的渲染?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆