来自perlmonks的交叉发布:
我必须在$ work处清理一些粗略的古代代码, 在我尝试制作新模块之前,如果有人知道某些合适的话,我会喜欢使用现有模块。
在运行时,我正在解析一个文件,以确定我需要对一组数据进行哪些处理。
如果我要编写一个模块,我会尝试更一般地(非DBI特定的),但我的确切用例是这样的:
我读取了一个SQL文件来确定要对数据库运行的查询。 我在顶部解析评论并确定
因此,当从db中获取时,程序会在返回数据之前应用各种(可能是堆叠的)转换。
目前,该代码是一个令人作呕的大而难的if子句系列 处理难以阅读或维护指令数组。
所以我想象的可能是一个解析这些线条的对象 (并另外暴露功能界面), 堆叠要应用的处理器列表, 然后能够在传递的数据上执行它。
可选地,可以有名称/类别选项, 这样一个对象就可以动态使用,只为给定的名称/类别/列堆栈处理器。
一个传统的人为例子:
$obj = $module->new();
$obj->parse("-- greeting:gsub: /hi/hello"); # don't say "hi"
$obj->parse("-- numbers:gsub: /\D//"); # digits only
$obj->parse("-- numbers:exchange: 1,2,3 one,two,three"); # then spell out the numbers
$obj->parse("-- when:date: %Y-%m-%d 08:00:00"); # format like a date, force to 8am
$obj->stack(action => 'gsub', name => 'when', format => '/1995/1996/'); # my company does not recognize the year 1995.
$cleaned = $obj->apply({greeting => "good morning", numbers => "t2", when => "2010116"});
每个处理器(gsub,日期,交换)将是一个单独的子例程。 可以定义插件以按名称添加更多插件。
$obj->define("chew", \&CookieMonster::chew);
$obj->parse("column:chew: 3x"); # chew the column 3 times
所以显而易见的第一个问题是,是否有人知道我可以使用的模块? 到目前为止我唯一能找到的是[mod:// Hash :: Transform], 但是因为我将确定在运行时动态执行哪些处理 我总是最终使用“complex”选项,我仍然需要构建解析器/堆栈器。
是否有人知道任何类似的模块,甚至是我可能想要利用/包装的温和相关的模块?
如果没有任何通用的公共消费(当然我的不是黑暗中唯一的那个), 是否有人建议记住事项或接口建议甚至其他可能的用途 除了从DBI,Text :: CSV等返回数据?
如果我最终编写一个新模块,是否有人有命名空间建议? 我觉得Data ::下的东西可能是合适的...... “可插拔”一词不断浮现在脑海中,因为我的用例让我想起了PAM, 但我真的没有任何好主意......
答案 0 :(得分:0)
首先,如果可能的话,我会尝试在SQL查询中尽可能多地放置格式。 像日期格式等的东西肯定应该在SQL中处理。
我知道的一个模块可以用于你的目的是Data::FormValidator。尽管is主要用于验证CGI参数,但它具有您需要的功能:您可以定义过滤器和约束,并以各种方式链接它们。并不意味着没有其他模块可供您使用,我只是不知道。
或者你可以做一些你已经暗示的事情。您可以定义某种命令类并将它们链接到各种数据输入上。我会沿着这些方向做点什么:
package MyDataProcessor;
use Moose;
has 'Transformations' => (
traits => ['Array'],
is => 'rw',
isa => 'ArrayRef[MyTransformer]',
handles => {
add_transformer => 'push',
}
);
has 'input' => (is => 'rw', isa => 'Str');
sub apply_transforms { }
package MyRegexTransformer;
use Moose;
extends 'MyTransformer';
has 'Regex' => (is => 'rw', isa => 'Str');
has 'Replacement' => (is => 'rw', isa => 'Str');
sub transform { }
# some other transformers
#
# somewhere else
#
#
my $processor = MyDataProcessor->new(input => 'Hello transform me');
my $tr = MyRegexTransformer->new(Regex => 'Hello', Replacement => 'Hi');
$processor->add_transformer($tr);
#...
$processor->apply_transforms;
答案 1 :(得分:0)
我不知道任何数据转换CPAN模块,所以我不得不自己动手工作。它比这复杂得多,但是按照类似的原则运作;它本质上是一个穷人的Informatica风格的ETL实现没有花哨的GUI ...配置是Perl哈希(Perl而不是XML,因为它允许我实现某些复杂的规则作为子程序引用)。
就命名空间而言,我会选择Data::Transform::*
答案 2 :(得分:0)
感谢大家的想法。
简短版本: 在尝试调整一些现有模块后,我最终抽象出了我自己的:Sub :: Chain。 它需要一些工作,但到目前为止我正在做我需要的工作。
长版: (摘自POD)
= head1 RATIONALE
这个模块最初是Data :: Transform :: Named, 一个命名的包装器(如Sub :: Chain :: Named) Data :: Transform(特别是Data :: Transform :: Map)。
当模块接近完成时,我意识到我使用的很少 Data :: Transform(及其文档提示) 我可能不想使用我使用的唯一部分)。 我还发现输出并不总是我所期望的。 根据可能的目的,我认为这似乎是合理的 Data :: Transform,这个模块只需要不同。
所以我试图更抽象地思考 并意识到该模块的本质并不依赖于 数据转换,但仅仅是简单子程序调用的继承。
然后我发现并考虑了Sub :: Pipeline 但需要能够使用相同的 在单个链中使用不同参数的命名子例程, 所以我似乎更容易坚持我写的代码 然后重命名它并进一步抽象它。
我还研究了开始开发的Rule :: Engine 在我搜索的时候。 但是,像Data :: Transform一样,它似乎比我需要的更复杂。 当我看到Rule :: Engine正在使用[非常优秀的] Moose时 我决定通过,因为我在一些非常旧的机器上工作 旧发行版和旧的perls以及有限的资源。 再一次,它似乎比我想要的要多得多。
=切
至于我原来的想法/例子中的“解析”方法, 我没有发现这是必要的,目前我正在使用像
这样的语法
$chain->append($sub, \@arguments, \%options)