Сменный / динамический модуль обработки данных / манипулирование / преобразование 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;
Другие вопросы по тегам