在现代 Perl 中编写异常类的最佳实践

2024-04-21

With Exception::Class https://metacpan.org/pod/Exception::Class,我可以将异常定义为类,并且一旦将它们加载到任何地方,它们就可以在任何地方使用。但是很多地方,包括 E::C 本身的文档,都建议使用Throwable https://metacpan.org/pod/Throwable如今。

Throwable是一个角色,所以我需要构建将其组成的类。Throwable::Factory https://metacpan.org/pod/Throwable::Factory对此有帮助,但我不知道如何使这些课程随处可用。看来 T::F 构建了返回不透明类名的子例程。我觉得我错过了最后一块拼图,但无法找到 T::F 实际使用的任何示例。


我似乎在寻找 4 件事。

  1. 声明异常类型的简单语法。
  2. 实现 Throwable 的异常。
  3. 异常对象中的额外功能,例如标签、自定义属性以及将属性传递给构造函数的简化。
  4. 通过类(全局可用)而不是函数(必须导入到每个模块中)来实例化异常。

Like Exception::Class https://metacpan.org/pod/Exception::Class, Throwable::Factory https://metacpan.org/pod/Throwable::Factory and Throwable::SugarFactory https://metacpan.org/pod/Throwable::SugarFactory提供了用于声明异常类型的简洁语法,但事实证明我可以没有它。Throwable::Factory https://metacpan.org/pod/Throwable::Factory事实上,它拥有我想要的一切,除了异常函数必须在它们使用的同一个文件中声明。它们是一种可抛出-可抛出的异常。我不想要这样。

中的一些额外功能Throwable::Factory https://metacpan.org/pod/Throwable::Factory异常来自 Throwable::Error,它是Throwable https://metacpan.org/pod/Throwable分配。其余的很容易被盗。 Throwable::Error 实际上是一个Moo https://metacpan.org/pod/Moo类,所以我们有一个获胜者。

我可以将所有异常类放在一个文件中并通过加载它use在我的应用程序的顶部。异常层次结构继承自 Throwable::Error 作为基类。因为这些是 Moo 类,所以向特定类添加自定义访问器很简单。我可以从 Throwable::Factory 剪切/粘贴我喜欢的额外功能。

package MyApp::Exceptions ;
use strict ;
use warnings ;

use Throwable::Error ;
use Types::Standard qw( Str ) ;
use Moo ;
use namespace::clean ;

use feature qw(signatures) ;
no warnings qw(experimental::signatures) ;

extends 'Throwable::Error' ;

with 'Role::Identifiable::HasTags' ;

has description => ( 
    is => 'ro', 
    isa => Str, 
    required => 1, 
    default => 'Generic exception',
    ) ;
   
# stack_trace() and message() inherited from Throwable::Error 
sub error   ($self) { $self->message  }
sub package ($self) { $self->stack_trace->frame(0)->package  }
sub file    ($self) { $self->stack_trace->frame(0)->filename  }
sub line    ($self) { $self->stack_trace->frame(0)->line  }

# sugar for ::HasTags 
sub has_tags ( $self, @wanted ) {
    $self->has_tag($_) || return 0 for @wanted ;
    return 1 ;
    }

# support shorthand instantiation eg Foo->throw($message, attr => $val);
around BUILDARGS => sub {
    my ( $orig, $class, @args ) = @_ ;
    return +{} unless @args ;
    return $class->$orig(@args) if @args == 1 ;
    unshift @args, 'message' if @args % 2 ;
    return $class->$orig( {@args} ) ;
    } ;

# ----- enduser exception classes -----
package SystemError ;
use Types::Standard qw( Int ) ;
use Moo ;
extends 'MyApp::Exceptions' ;
has code           => ( is => 'ro', isa => Int->where('$_ >= 0'), default => 1 ) ;
has '+description' => ( default => 'A system error' ) ;

package FileError ;
use Types::Standard qw( InstanceOf ) ;
use Moo ;
extends 'SystemError' ;
has '+code'        => ( default => 2 ) ;
has '+description' => ( default => 'A file error' ) ;
has file           => ( is => 'ro', required => 1, isa => InstanceOf['Path::Tiny'] ) ;

1 ;

只要在某个地方,我说过use MyApp::Exceptions;,现在我到处都可以说:

use Nice::Try ;

try {
    something() or SystemError->throw("Problem trying to do something", 
        code => 7, 
        tags => [qw(something broke)],
        ) ;
    }

catch ( SystemError $e where { $_->has_tags(qw(something broke)) }) {
    fix_it($e) ;
    }

catch ( SystemError $e where { $_->has_tag('something') }) {
    repair_it($e) ;
    }

catch ( FileError $e ) {
    warn sprintf "Problem doing something() with file %s: %s", 
        $e->file->basename, $e->message ;
    }

catch ( $e ) {
    die "Give up! $e" ;
    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在现代 Perl 中编写异常类的最佳实践 的相关文章

随机推荐

  • 模板化 lambda 的显式实例化[重复]

    这个问题在这里已经有答案了 我刚刚遇到显式实例化模板 lambda 的问题 下面的代码无法编译 但我无法弄清楚这种情况下出了什么问题
  • 如何删除所有超过 2 天的空文件夹?

    我制作了一个脚本 删除路径中带有子文件夹的所有空文件夹 现在我必须做的是 如果一个文件夹是 2 天前创建的 并且它是空的 则应该将其与其他早于 2 天的空文件夹一起删除 如果不是 则不应删除它 我还需要 想要将已删除的文件夹写入日志中 我用
  • ERM:三元关系中的基数

    如何读取和 或指定实体关系模型 陈表示法 三元关系中的基数 最小 最大 例如 一位领导与他的相关员工一起考察了多项资格认证 现在 我想知道如何在最小 最大 表示法中指定基数 这是给定基数的另一个示例 我想知道如何阅读它 三元关系可以解读为
  • 选择组合框项目时启用文本框

    我想在选择组合框项时启用文本框 请注意 组合框项目未定义 而是我在组合框中使用项目源来获取组合框项目的列表 我想在选择组合框项目时更改文本框的属性 评论粘贴到原始问题
  • 为什么会话 cookie 在从域提供服务时有效,但在使用 IP 时却无效?

    我有一个 Flask 应用程序 其中的会话在我的本地开发计算机上运行良好 但是 当我尝试将其部署在亚马逊服务器上时 会话似乎不起作用 更具体地说 未设置会话cookie 不过 我可以设置普通的 cookie 我确保我有一个静态安全密钥 正如
  • 为对象序列提供 JsonFormat

    我试图在这里找到一些帮助来应用 DefaultJsonProtocol 的 JsonFormat 扩展 包含对象序列的类 所以对于课程来说 class Person val name String val adresses Seq Adre
  • 如何在oracle DB中存储日文字符?

    我想将日语 或任何语言 字符存储在我的 Oracle 数据库表的一列中 我使用 varchar2 作为数据类型 当我尝试将此字符 插入到该列时 它存储为 不知道该怎么办 需要帮忙 Note 我尝试将数据类型更改为 nvarchar2 仍然不
  • 适用于 Windows 的 SVN 挂钩

    我用谷歌搜索了一下 发现确实没有适用于 Windows 的 SVN hooks 资源 所以我想我应该在这里创建一个维基来集中它 如果您贡献 请务必注明 钩子的名称 脚本的作用 实际脚本 注意 我怀疑发布史诗般的脚本不会有用 防止提交空注释
  • 具有 Jetty 连接器的 Restlet 2.0.8 不会恢复 SSL 会话,而 Simple 连接器会恢复 SSL 会话

    有谁知道这是为什么 或者如何解决它 我正在使用 android 通过 httpclient 连接 简单连接器恢复连接很好 但 Jetty 每次都会执行新的握手 代码是相同的 这只是我在构建路径上获得的连接器 不断地重做握手会消耗大量的数据和
  • 如何使弹丸转弯时带有弧线

    我有一门大炮 可以以抛物线弧线发射子弹 现在 当我发射子弹时 子弹的旋转速度与从大炮中发射时的旋转速度相同 如何使子弹在空气中飞行时沿着弧线旋转 我尝试了以下作为在项目符号上运行的脚本 附件1 public class PointingBe
  • SQL Server Reporting Services 2008 R2 始终显示登录提示

    每当我尝试通过 URL 访问 SSRS 2008 R2 即在网络上发布后 时 访问报告时总是显示登录提示 开发环境中不会出现该问题 如何防止在我尝试访问报告时显示此登录提示 目前 我们正在通过提供用户名和密码来解决这个问题
  • 模拟器未切换到下一个活动

    我对 Android 编程完全陌生 我正在做一个简单的应用程序 其中显示启动屏幕 然后显示登录屏幕 问题是模拟器不会超出启动屏幕 Android 清单
  • Groovy - XmlNodePrinter 打印空白文件

    我正在尝试将格式化的 xml 打印到文件中 但我的 XmlNodePrinter 仅打印一个空白文件 我认为我传入的 xml 对象已正确填充 我可以使用 StreamingMarkupBuilder 打印它 但它的格式全部在一行上 我不知道
  • 如何设置 Xamarin Picker 中项目列表的样式(在 Android 中)

    我有一个 Xamarin Android 应用程序 它使用选取器从值列表中进行选择 我一直在改变应用程序的风格 但遇到了选择器的问题 虽然我可以设置 TextColor 但无法设置占位符文本的颜色 在搜索帮助后 我实现了一个自定义渲染器 现
  • Jekyll:不允许操作@apply2files

    我正在使用 Windows 10 的 Linux 子系统 我在其中安装了 Jekyll 但是当我运行时bundle exec jekyll serve它给了我 jekyll 3 8 6 Error Operation not permitt
  • 检测视口单元(使用modernizr或普通js)并提供适当的样式表

    实际上 三周以来我一直在尝试解决一个问题 我正在尝试测试对大众单位的支持 并在浏览器不支持该单位时提供单独的样式表 我阅读了modernizr教程并且熟悉modernizr css检测 但是我在网上没有找到vh单位 视口相对单位 的测试 所
  • 不同子域上的会话 cookie 是否算作第 3 方?

    假设我有一个网站www example com其中有一个 IFRAME 指向 ASP NET 站点myapp othersite com 据我所知 这会导致会话和第三方 cookie 出现问题 如果我将嵌入式应用程序移至myapp exam
  • Python 格式化小数,具有最少小数位数

    我有一些DecimalPython 中的实例 我希望将它们格式化为 Decimal 1 gt 1 00 Decimal 12 0 gt 12 00 Decimal 314 1 gt 314 10 Decimal 314 151 gt 314
  • 使用 NHibernate 在延迟加载场景中使用 Castle.DynamicProxy 实现 IDataErrorInfo

    我已经使用 Castle DynamicProxy IIterceptor 实现了 IDataErrorInfo 接口 我还实现了一个 NHibernate 拦截器 它使用该拦截器实例化我的实体 问题在于延迟加载的实体 这些是使用 nhib
  • 在现代 Perl 中编写异常类的最佳实践

    With Exception Class https metacpan org pod Exception Class 我可以将异常定义为类 并且一旦将它们加载到任何地方 它们就可以在任何地方使用 但是很多地方 包括 E C 本身的文档 都