【问题标题】:Module for executing postponed initialization code用于执行延迟初始化代码的模块
【发布时间】:2014-11-20 22:41:29
【问题描述】:

在哪里放置初始化代码(连接到数据库、生成内容、加载数据文件等)?

以下是一些现有选项:

  1. 将其放入相关模块中。这将在模块为used 时执行BEGIN{} 中的代码

(+) 良好的封装性。

(-) 一切都与数据库、配置、特定文件位置等相关联。难以隔离单元测试,更难运行代码 sn-ps 来查找错误,如 perl -MFoo -d -we 'Foo->new'

  1. 将其放入单独的脚本中(startup.pl 等)

(-) 代码远离使用的地方,容易忘记。

(-) 初始化全有或全无。

  1. 项目中每个模块中的startup()(或其他名称)例程。

(-) 还是很容易忘记运行它。

  1. 使用 Perl 的内置 INIT 块。

这就是问题所在(当然,Apache 也是如此):

 bash$ plackup -e 'use warnings; INIT{ warn "foo"; }; sub { warn "here"; return [200, [], []] };'
 Too late to run INIT block at (eval 7) line 1.
 HTTP::Server::PSGI: Accepting connections at http://0:5000/
 here at (eval 7) line 1.
 127.0.0.1 - - [20/Nov/2014:14:18:08 +0200] "GET / HTTP/1.1" 200 - "-" "Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:33.0) Gecko/20100101 Firefox/33.0"

注意Too late to call INIT 警告,输出中没有“foo”的迹象。

现在我想要一个如下使用的模块:

在项目的模块中:

use Init::Queue sub { 
    get_dbh(); 
    load_file();
    build_cache(); 
}; # postpone till explicitly called

在生产/初始化代码中:

Init::Queue->startup(); 
# this executes all startup blocks,
# in order of appearance

有这样的模块吗?如果没有,是否需要?或者有没有我忽略的更简单的方法?

【问题讨论】:

    标签: perl


    【解决方案1】:

    嗯,答案是“视情况而定”。但就个人而言,我倾向于采用“首次使用时初始化”的方法。当您使用面向对象时,这相对容易 - 挂钩构造函数并让它进行设置。

    对于非 OO perl,我实际上倾向于这样做:

    {
        my $thing_to_init;
        sub init { 
            $thing_to_init = 1;      
        }
    
       sub call_some_function {
           init() unless defined $thing_to_init; 
    
            #do everything else
        }
    }
    

    因为它位于闭包内,所以无法从模块命名空间访问 $thing_to_init,但您可以:手动调用 init() 子程序,或者让事物在启动时自行初始化。

    【讨论】:

    • 是的,惰性初始化是我错过的。但是,如果我的应用程序有缺陷和/或配置错误,我也希望我的应用程序在启动时大声失败。不过,我没有在原始消息中说明。
    • 嗯,那很难。模块中的 BEGIN 块似乎是明智的,但我不确定那时你可以传递多少配置给它。也许有一个“默认配置”和一个要重新配置的覆盖?
    猜你喜欢
    • 1970-01-01
    • 2020-05-10
    • 1970-01-01
    • 1970-01-01
    • 2011-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-08
    相关资源
    最近更新 更多