Domanda

Cross-postato da PerlMonks:

Devo pulire un po ', antico codice lordo a $ lavoro, e prima che io cerco di fare un nuovo modulo mi piacerebbe utilizzare uno esistente se qualcuno sa di qualcosa di appropriato.

In fase di runtime sto analisi di un file per determinare che cosa la lavorazione ho bisogno di fare su un insieme di dati.

Se dovessi scrivere un modulo vorrei cercare di farlo più genericamente (non DBI-specifico), ma il mio esatto caso d'uso è questo:

ho letto un file SQL per determinare la query da eseguire sul database. I commenti parse in alto e stabilire che

     
  • colonna A deve avere una s /// applicata,
  •  
  • esigenze colonna B da trasformare per assomigliare ad una data del dato formato,
  •  
  • colonna C ottiene una sorta di tr ///.
  •  
  • Inoltre cose possono essere concatenati in modo che la colonna D forza s ///, poi dire se non è 1 o 2, impostarlo 3.

Così, quando il recupero dal db il programma applica le varie trasformazioni (possibilmente sovrapposti) prima di restituire i dati.

Attualmente il codice è una serie disgustosamente grande e difficile se clausole elaborazione orrendamente difficile da leggere o mantenere array di istruzioni.

Quindi quello che sto immaginando è forse un oggetto che analizzare queste linee (Ed esporre inoltre un'interfaccia funzionale), impilare l'elenco dei processori di applicare, quindi in grado di eseguire su un pezzo passato di dati.

Opzionalmente ci potrebbe essere un opzione del nome / categoria, in modo che un oggetto potrebbe essere usato dinamicamente per impilare trasformazione solo per il nome / categoria / colonna.

Un esempio tradizionalmente escogitato:

$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"});  

Ogni processore (gsub, data, cambio) sarebbe una subroutine separata. Plugin potrebbero essere definiti per aggiungere più per nome.

$obj->define("chew", \&CookieMonster::chew);  
$obj->parse("column:chew: 3x"); # chew the column 3 times  

Così l'ovvia prima domanda è, qualcuno sa di un modulo là fuori che potrei usare? L'unica cosa che sono riuscito a trovare finora è [mod: // Hash :: Trasforma], ma dal momento che sarei determinare quali di elaborazione per fare in modo dinamico in fase di esecuzione Vorrei sempre finire con il l'opzione "complessa" e mi piacerebbe ancora di costruire il parser / raccoglitore.

C'è qualcuno a conoscenza di eventuali moduli simili o anche un modulo leggermente correlato che potrei voler utilizzare / involucro?

Se non c'è niente fuori generico là per il consumo pubblico (sicuramente la mia non è l'unico nel darkpan), Qualcuno ha qualche consiglio per le cose da tenere a mente o di interfaccia suggerimenti o anche altri possibili usi Oltre munging il ritorno di dati da DBI, Text :: CSV, ecc?

Se finisco scrivendo un nuovo modulo, qualcuno ha suggerimenti dello spazio dei nomi? Credo che qualcosa sotto dati :: è probabilmente appropriata ... la parola "pluggable" continua a venire in mente perché il mio caso d'uso mi ricorda PAM, ma io davvero non ho tutte le idee buone ...

     
  • Dati :: :: Processore Pluggable?
  •  
  • Dati :: :: munging configurabile?
  •  
  • I :: :: Chew dati?
È stato utile?

Soluzione 3

Grazie a tutti per i loro pensieri.

La versione corta: Dopo aver cercato di adattare alcuni moduli esistenti ho finito per astrarre la mia: Sub :: catena. Ha bisogno di qualche lavoro, ma sta facendo quello che mi serve finora.

La versione lunga: (Un estratto dal POD)

= head1 MOTIVAZIONI

Questo modulo è iniziato come dati :: :: Trasforma Nome, un involucro di nome (come sub :: :: catena nome) intorno Data :: Transform (e in particolare i dati :: :: Transform Mappa).

Poiché il modulo è stato quasi finito mi resi conto che stava usando molto poco di dati :: Transform (e la relativa documentazione suggerisce che Probabilmente non si desidera utilizzare l'unica parte che io ho usando). Ho anche scoperto che l'uscita non era sempre quello che mi aspettavo. Ho deciso che sembrava ragionevole secondo allo scopo probabile dei Dati :: Transform, e questo modulo semplicemente doveva essere diverso.

Così ho cercato di pensare in modo più astratto e comprese che l'essenza del modulo non era legato trasformazione dei dati, ma semplicemente la successione di subroutine chiamate semplici.

Ho poi trovato e considerato Sub :: Pipeline ma aveva bisogno di essere in grado di utilizzare lo stesso chiamato subroutine con argomenti diversi in una singola catena, così c'è sembrato più facile per me da attaccare con il codice che avevo scritto e basta rinominarlo e astratto è un po 'oltre.

Ho anche guardato in regola :: motore che cominciava sviluppo al tempo ero alla ricerca. Tuttavia, come Data :: Transform, è sembrato più complesso di quello che mi serviva. Quando ho visto che la regola :: Motore stava usando [molto eccellente] Moose Ho deciso di passare da quando stavo facendo un lavoro su una serie di macchine molto vecchie con le vecchie distribuzioni e vecchie perle e risorse limitate. Anche in questo caso, mi sembrava di essere molto di più di quello che stavo cercando.

= taglio

Per quanto riguarda il metodo di "parse" nella mia idea / esempio originale, Non ho trovato che per essere necessario, e sto attualmente utilizzando la sintassi come

$chain->append($sub, \@arguments, \%options)

Altri suggerimenti

Per prima cosa mi piacerebbe provare a posto come gran parte della formattazione possibile nelle query SQL, se possibile. Cose come il formato della data, ecc sicuramente devono essere trattati in SQL.

Fuori superiore della mia testa un modulo che conosco e che potrebbero essere utilizzate per il vostro scopo è Data :: FormValidator . Anche se è si rivolge principalmente a convalidare i parametri CGI, ha le funzionalità necessarie: è possibile definire filtri e vincoli e concatenare in vari modi. Non significa che non c'è altri moduli per te scopo, io proprio non lo so.

o si può fare qualcosa di quello che già si è accennato a. È possibile definire una sorta di classi di comando e li catena su vari ingressi dati. Farei qualcosa in questo senso:

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;

Io non sono a conoscenza di tutti i dati trasformare moduli CPAN, così ho dovuto rotolare il mio lavoro. E 'stato molto più complicato di così, ma opera sotto un principio simile; era fondamentalmente implementazione di un uomo povero di stile Informatica ETL sans la GUI di fantasia ... la configurazione era hash Perl (Perl, invece di XML in quanto mi ha permesso di attuare alcune regole complesse come riferimenti a subroutine).

Per quanto riguarda i namespace, mi piacerebbe andare per Data::Transform::*

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top