Сменный / динамический модуль обработки данных / манипулирование / преобразование Perl?
Кросс-пост от Perlmonks:
Я должен очистить какой-то грубый, древний код на рабочем месте, и прежде чем попытаться создать новый модуль, я бы хотел использовать существующий, если кто-нибудь знает что-то подходящее.
Во время выполнения я анализирую файл, чтобы определить, какую обработку мне нужно выполнить для набора данных.
Если бы я написал модуль, я бы попытался сделать это более обобщенно (не специфично для DBI), но мой точный вариант использования таков:
Я прочитал файл SQL, чтобы определить, какой запрос нужно выполнить для базы данных. Я анализирую комментарии вверху и определяю, что
- столбец А должен иметь примененный ///,
- столбец B необходимо преобразовать, чтобы он выглядел как дата заданного формата,
- столбец C получает вид tr ///.
- Кроме того, все может быть приковано цепочкой, чтобы столбец D мог иметь ///, а затем сказать, если это не 1 или 2, установить его в 3.
Таким образом, при извлечении из базы данных программа применяет различные (возможно, суммированные) преобразования перед возвратом данных.
В настоящее время код представляет собой отвратительно большую и сложную серию операторов 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, date, exchange) будет отдельной подпрограммой. Плагины могут быть определены, чтобы добавить больше по имени.
$obj->define("chew", \&CookieMonster::chew);
$obj->parse("column:chew: 3x"); # chew the column 3 times
Итак, первый очевидный вопрос: кто-нибудь знает модуль, который я мог бы использовать? Единственное, что мне удалось найти, это [mod://Hash::Transform], но, поскольку я буду определять, какую обработку выполнять динамически во время выполнения, я всегда буду использовать "сложный" параметр, и я мне все равно придется собирать парсер / укладчик.
Кто-нибудь знает о каких-либо подобных модулях или даже слегка связанных модулях, которые я мог бы использовать / обернуть?
Если нет ничего общего для общественного потребления (конечно, мой не единственный в темном пространстве), есть ли у кого-нибудь какие-либо советы по поводу вещей, которые следует иметь в виду, или по интерфейсам, и даже по другим возможным применениям, кроме манипулирования возвратом данных из DBI, Текст::CSV и т. Д.?
Если я закончу писать новый модуль, есть ли у кого-нибудь предложения по пространству имен? Я думаю, что что-то в Data::, вероятно, уместно... слово "pluggable" приходит на ум, потому что мой вариант использования напоминает мне PAM, но у меня действительно нет хороших идей...
- Data:: Processor:: Pluggable?
- Data:: Munging:: Настраивается?
- Я:: жевать:: данные?
3 ответа
Спасибо всем за их мысли.
Короткая версия: после попытки адаптировать несколько существующих модулей я закончил абстрагировать свой собственный: Sub::Chain. Нужно немного поработать, но я делаю то, что мне нужно.
Длинная версия:(выдержка из POD)
= head1 ОБОСНОВАНИЕ
Этот модуль начинался как Data::Transform::Named, именованная оболочка (например, Sub::Chain::Named) вокруг Data::Transform (и, в частности, Data::Transform::Map).
Поскольку модуль был почти готов, я понял, что использую очень мало Data::Transform (и его документация предполагает, что я, вероятно, не захочу использовать единственную часть, которую использует II). I also found that the output was not always what I expected. Я решил, что это кажется разумным в соответствии с вероятной целью Data:: Transform, и этот модуль просто должен быть другим.
So I attempted to think more abstractly and realized that the essence of the module was not tied to data transformation, but merely the succession of simple subroutine calls.
Затем я нашел и рассмотрел Sub::Pipeline, но мне нужно было иметь возможность использовать подпрограмму с одним и тем же именем с разными аргументами в одной цепочке, поэтому мне было проще придерживаться кода, который я написал, и просто переименовать его и абстрагировать немного дальше.
I also looked into Rule::Engine which was beginning development at the time I was searching. Однако, как и Data:: Transform, он казался более сложным, чем мне было нужно. Когда я увидел, что Rule:: Engine использует [очень превосходного] Moose, я решил пропустить его, поскольку работал над множеством очень старых машин со старыми дистрибутивами и старыми perl и ограниченными ресурсами. Опять же, казалось, что это намного больше, чем я искал.
=cut
Что касается метода "parse" в моей первоначальной идее / примере, я не нашел в этом необходимости, и в настоящее время использую синтаксис
$chain->append($sub, \@arguments, \%options)
Я не знаю ни о каких модулях CPAN для преобразования данных, поэтому мне пришлось свернуть свои собственные для работы. Это было значительно сложнее, чем это, но действовало по аналогичному принципу; в основном это была реализация для ETL в стиле Informatica без необычного графического интерфейса... конфигурация была хэшей Perl (Perl вместо XML, поскольку она позволяла мне реализовывать некоторые сложные правила в виде ссылок на подпрограммы).
Что касается пространства имен, я бы пошел на Data::Transform::*
Сначала я постараюсь разместить как можно больше форматирования в запросах SQL. Такие вещи, как формат даты и т. Д., Безусловно, должны обрабатываться в SQL.
Вдобавок ко всему, модуль, который я знаю и который можно использовать для ваших целей, - это Data:: FormValidator. Несмотря на то, что он в основном предназначен для проверки параметров 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;