view release on metacpan or search on metacpan
MANIFEST
Makefile.PL
readme
test.pl
lib/ARSObject.pod
lib/ARSObject.pm
META.yml Module meta-data (added by MakeMaker)
lib/ARSObject.pm view on Meta::CPAN
,-vfbase => # Var files base
(do{ my $v =$^O eq 'MSWin32' ? scalar(Win32::GetFullPathName($0)) : $0;
$v =~/^(.+?)\.[^\\\/]*$/ ? "$1-" : "$v-"
})
#,-storable =>undef # Use Storable module for cache files?
,-schgen => 1 # 1 - use vfname('meta') for '-meta', generate it from ARS if not exists.
# 2 - renewable 'meta' smartly
# 3 - renew meta always
# [schema,...] - list to renew
,-schfdo => 0 # Include display only fields into schema (AR_FIELD_OPTION_DISPLAY)
,-meta => {} # Forms metadata from ARS:
# {formName}->{-fields}->{fieldName}=>{}
# {formName}->{-fldids}->{fieldId}=>{}
# Additional parameters may be:
# ,'fieldLbl' =>label
# ,'fieldLbll'=>label localised
# ,'fieldLblc'=>label catenation/comment
# ,'fieldLbv' =>labels of values
# ,'fieldLbvl'=>labels of values localised
# ,'indexUnique'
# ,'strOut'|'strIn'=>sub(self,form,{field},$_=val){}
lib/ARSObject.pm view on Meta::CPAN
,-metax => # Exclude field schema parameters from '-meta'
['displayInstanceList','permissions']
,-metaid => {} # Commonly used fields with common names and value translation
,-metadn => {} # {fieldId | fieldName =>
# {fieldName=>'name',FieldId=>id
# ,strIn=>sub(self,form,{field},$_=val){}
# ,strOut=>sub(self,form,{field},$_=val){}
# },...}
,-maxRetrieve => 0 # ARS::ars_GetListEntry(maxRetrieve)
,-entryNo => undef # Logical number of entry inserted
,-strFields => 1 # Translate fields data using 'strIn'/'strOut'/'-meta'?
# 1 - 'enumLimits', 2 - 'fieldLbvl' before 'enumLimits'
,-cmd =>'' # Command running, for err messages, script local $s->{-cmd}
,-die =>undef # Error die/warn, 'Carp' or 'CGI::Carp...'
# ,-diemsg => undef #
,-warn=>undef # , see set() and connect() below
# ,-warnmsg => undef #
,-cpcon=>undef # Translation to console codepage sub{}(self, args) -> translated
,-echo=>0 # Echo printout switch
,-dbi=>undef # DBI object, by dbiconnect()
,-dbiconnect =>undef #
lib/ARSObject.pm view on Meta::CPAN
sub arsquot { # Quote string for ARS
return('NULL') if !defined($_[1]);
my $v =$_[1];
$v =~s/"/""/g;
$v =~/^\d+$/ ? $v : ('"' .$v .'"');
}
sub dsquot { # Quote data structure
$#_ <2 # (self, ?'=>', data struct)
? dsquot($_[0],'=> ',$_[1])
: !ref($_[2]) # (, hash delim, value) -> stringified
? strquot($_[0],$_[2])
: ref($_[2]) eq 'ARRAY'
? '[' .join(', ', map {dsquot(@_[0..1],$_)
} @{$_[2]}) .']'
: ref($_[2]) eq 'HASH'
? '{' .join(', ', map {$_ .$_[1] .dsquot(@_[0..1],$_[2]->{$_})
} sort keys %{$_[2]}) .'}'
: strquot($_[0],$_[2])
}
sub dsquot1 { # Quote data structure, defined elements only
$#_ <2 # (self, ?'=>', data struct)
? dsquot1($_[0],'=> ',$_[1])
: !ref($_[2]) # (, hash delim, value) -> stringified
? strquot($_[0],$_[2])
: ref($_[2]) eq 'ARRAY'
? '[' .join(', ', map {defined($_) ? dsquot1(@_[0..1],$_) : ()
} @{$_[2]}) .']'
: ref($_[2]) eq 'HASH'
? '{' .join(', ', map {defined($_[2]->{$_}) ? $_ .$_[1] .dsquot1(@_[0..1],$_[2]->{$_}) : ()
} sort keys %{$_[2]}) .'}'
: strquot($_[0],$_[2])
}
sub dsdump { # Data structure dump to string
my ($s, $d) =@_; # (data structure) -> dump string
eval('use Data::Dumper');
my $o =Data::Dumper->new([$d]);
$o->Indent(1);
$o->Deepcopy(1);
$o->Dump();
}
sub dsparse { # Data structure dump string to perl structure
my ($s, $d) =@_; # (string) -> data structure
eval('use Safe; 1')
&& Safe->new()->reval($d)
}
sub dscmp { # Compare data structures
my($s, $ds1, $ds2) =@_;
return(1) if (defined($ds1) && !defined($ds2)) ||(defined($ds2) && !defined($ds1));
return(0) if !defined($ds1) && !defined($ds2);
return(1) if (ref($ds1) ||'') ne (ref($ds2) ||'');
return($ds1 cmp $ds2) if !ref($ds1);
return(dsquot($s,$ds1) cmp dsquot($s,$ds2)) if ref($ds1) eq 'ARRAY';
return(dsquot($s,$ds1) cmp dsquot($s,$ds2)) if ref($ds1) eq 'HASH';
$ds1 cmp $ds2
}
lib/ARSObject.pm view on Meta::CPAN
sub vfname { # Name of variables file
# (varname|-slot) -> pathname
return($_[0]->{-vfbase}) if !$_[1];
my $v =$_[1]; $v =~s/[\s.,:;|\/\\?*+()<>\]\["']/_/g;
$_[0]->{-vfbase} .($v =~/^-(.+)/ ? ($1 .($_[2] ||'.var')) : ($v .($_[2] ||'.var')))
}
sub vfstore { # Store variables file
# (varname, {data}) -> success
# (-slot) -> success
my($s,$n,$d)=@_;
$d =$s->{$n} if !$d && ($n =~/^-/);
my $f =$s->vfname($n, '.new');
my $r;
if (($n =~/^-/) && exists($s->{"${n}-storable"}) ? $s->{"${n}-storable"} : $s->{-storable}) {
for (my $i =0; ($i <$fretry) && eval("use Storable; 1"); $i++) {
$r =Storable::store($d, $f);
last if $r;
}
lib/ARSObject.pm view on Meta::CPAN
last if $rr
}
return(&{$s->{-die}}($s->efmt('$!',$s->{-cmd},undef,'rename',$f,'*.var')))
if !$rr
}
$r
}
sub vfload { # Load variables file
# (varname|-slot, ?{use default} | load default, ?renew | renew seconds) -> {data}
my($s,$f,$d,$nn) =@_; # -slot-calc, -slot-store
my $k =($f =~/^-/ ? $f : undef);
$f =$s->vfname($f);
if ($nn && $nn >1) {
my @st =stat($f);
$nn =0 if $st[9] && (time() -$st[9] <$nn);
}
if ($d && ($nn || !-f $f)) {
if (ref($d)) {
$s->vfstore($k, $d =ref($d) eq 'CODE' ? &$d($s,$k) : $d);
lib/ARSObject.pm view on Meta::CPAN
sub vfrenew { # Renew variables file
my($s,$f,$nn) =@_; # (-slot, ?period seconds) -> vfload
return(1) if $f !~/^-/;
vfload($s,$f,1,$nn ||1);
}
sub vfclear { # Clear vfdata() and vfhash()
my($s,$f) =@_; # (-slot, ?period seconds) -> vfload
return(1) if $f !~/^-/;
delete($s->{$f});
foreach my $k (keys %$s) {
next if $k !~/^\Q$f\E[\/].+/;
delete $s->{$k};
}
1;
}
sub vfdata { # Access to array data from variables file
# automatically load using vfload().
# (-slot) -> [array]
# (-slot, filter sub{}(self, -slot, index, $_=value)) -> [array]
vfload($_[0], $_[1], 1) if !$_[0]->{$_[1]} || (ref($_[0]->{$_[1]}) eq 'CODE');
if ($_[2]) {
if (ref($_[2]) eq 'CODE') {
local $_;
local $_[0]->{-cmd} =($_[0]->{-cmd} ? $_[0]->{-cmd} .': ' : '')
."vfdata('$_[1]', sub{})";
my ($rr, $v);
if (ref($_[0]->{$_[1]}) eq 'ARRAY') {
$rr =[];
for(my $i=0; $i<=$#{$_[0]->{$_[1]}}; $i++) {
if (!defined(eval{$v =&{$_[2]}($_[0], $_[1], $i, $_ =$_[0]->{$_[1]}->[$i])}) && $@) {
last if $@ =~/^last[\r\n]*$/;
next if $@ =~/^next[\r\n]*$/;
return(&{$_[0]->{-die}}($_[0]->efmt($@,$_[0]->{-cmd})));
}
elsif ($v) {
lib/ARSObject.pm view on Meta::CPAN
return($rr)
}
else {
return($_[0]->{$_[1]}->[$_[2]])
}
}
$_[0]->{$_[1]}
}
sub vfhash { # Access to hash of array data from variables file
# automatically formed in memory using vfdata().
# (-slot, key name) -> {hash from vfdata()}
# (-slot, key name => key value) -> {key=>value,...}
# (-slot, key name => key value => elem name ) -> elem value
# (-slot, key name => filter sub{}(self, -slot, key, $_ = value)) -> {key=>value,...}
my($s, $f, $k, $v, $e) =@_;
return(&{$s->{-die}}($s->efmt('Key name needed',undef,undef,'vfhash',$f))) if !$k;
$s->vfload($f, 1) if !$s->{$f} ||(ref($s->{$f}) eq 'CODE');
my $kk ="$f/$k";
if (!$s->{$kk}) {
$s->{$kk} ={};
if (ref($s->{$f}) eq 'ARRAY') {
lib/ARSObject.pm view on Meta::CPAN
? $s->{$kk}
: !ref($s->{$kk}->{$v})
? $s->{$kk}->{$v}
: defined($e)
? $s->{$kk}->{$v}->{$e}
: $s->{$kk}->{$v}
}
sub vfdistinct {# Distinct values from vfdata() field.
# (-slot, key name) -> [keys %{vfhash(...)}]
# (-slot, key name => filter sub{}(self, -slot, key, $_ = value)) -> [keys %{vfhash(...)}]
my($s, $f, $k, $v) =@_;
my(%rh, $t);
local $_;
local $_[0]->{-cmd} =($_[0]->{-cmd} ? $_[0]->{-cmd} .': ' : '')
."vfdistinct('$f', '$k', sub{})";
$s->vfload($f, 1) if !$s->{$f} ||(ref($s->{$f}) eq 'CODE');
if (ref($s->{$f}) eq 'ARRAY') {
for(my $i=0; $i<=$#{$s->{$f}}; $i++) {
lib/ARSObject.pm view on Meta::CPAN
$s->{-srv}, $s->{-usr}, $s->{-pswd}, $s->{-lang}
, '' # , join('-', ($ENV{COMPUTERNAME} ||$ENV{HOSTNAME} ||eval('use Sys::Hostname;hostname') ||'localhost'), getlogin() || $> || '', $$, $^T, time())
, 0, 0)
|| return(&{$s->{-die}}($s->efmt($ARS::ars_errstr,$s->{-cmd},undef,'ars_Login', map {$_=>$s->{$_}} qw(-srv -usr -lang))));
$s->{-ctrl} && ARS::ars_SetSessionConfiguration($s->{-ctrl}, &ARS::AR_SESS_OVERRIDE_PREV_IP, 1);
$s->arsmeta();
$s
}
sub disconnect { # Disconnect data servers
my $s =shift;
$s->{-ctrl} && eval{ars_Logoff($s->{-ctrl})};
$s->{-ctrl}=undef;
$s->{-dbi} && eval{$s->{-dbi}->disconnect()};
$s->{-dbi} =undef;
}
sub arsmeta { # Load/refresh ARS metadata
my $s =shift; # -srv, -usr, -pswd, -lang
$s->set(@_);
local $s->{-cmd} =($s->{-cmd} ? $s->{-cmd} .': ' : '')
.($s->{-schgen} ? "dumper('" .$s->vfname('meta') ."')" : 'arsmeta()');
if (ref($s->{-schgen})
|| ($s->{-schgen} && ($s->{-schgen} >1))
|| (!-e $s->vfname('-meta'))
) {
#
# Data types:
lib/ARSObject.pm view on Meta::CPAN
}
my $ix ={map {$_->{unique}
&& (scalar(@{$_->{fieldIds}}) ==1)
? ($_->{fieldIds}->[0] => 1)
: ()} @{$fa->{indexList}}};
my %ff =ARS::ars_GetFieldTable($s->{-ctrl}, $f);
!%ff && return(&{$s->{-die}}($s->efmt($ARS::ars_errstr,$s->{-cmd},undef,'ars_GetFieldTable',$f)));
foreach my $ff (sort keys %ff) {
my $fm =ARS::ars_GetField($s->{-ctrl},$f,$ff{$ff})
|| return(&{$s->{-die}}($s->efmt($ARS::ars_errstr,$s->{-cmd},undef,'ars_GetField',$f,$ff)));
# 'fieldId', 'fieldName', 'dataType'
next if !$fm->{dataType}
|| ($fm->{dataType} =~/^(trim|control|table|column|page)/);
next if !$s->{-schfdo} && $fm->{option} && ($fm->{option} == 4); # AR_FIELD_OPTION_DISPLAY
$s->{-meta}->{$f}->{-fields}->{$ff} =$fm;
$s->{-meta}->{$f}->{-fields}->{$ff}->{indexUnique} =$fm->{fieldId}
if $ix->{$fm->{fieldId}}
|| ($fm->{fieldId} eq '1'); # || '179'?
if ($fm->{displayInstanceList}->{dInstanceList}
) {
# foreach my $i (defined($vli) || defined($vll) ? (map {defined($_) ? $_ : ()} $vli, $vll) : (0..$#{$fm->{displayInstanceList}->{dInstanceList}})) {
for (my $i =0; $i <=$#{$fm->{displayInstanceList}->{dInstanceList}}; $i++) {
next if !$fm->{displayInstanceList}->{dInstanceList}->[$i]->{props};
lib/ARSObject.pm view on Meta::CPAN
$vfu && $s->vfstore('-meta')
}
# print $s->cpcon($s->dsdump($s->{-meta})), "\n"; exit(0);
}
elsif (-e $s->vfname('meta')) {
$s->vfload('-meta');
# print $s->cpcon($s->dsdump($s->{-meta})), "\n"; exit(0);
}
else {
$s->{-meta} ={};
return(&{$s->{-die}}($s->efmt('No metadata',$s->{-cmd})))
}
$s->arsmetaix() if $s->{-meta};
}
sub arsmetaix { # Index ARS metadata
my $s =shift;
if ($s->{-meta}) {
foreach my $f (keys %{$s->{-meta}}){
next if $f =~/^-/;
$s->{-meta}->{$f}->{-fldids} ={}
if !$s->{-meta}->{$f}->{-fldids};
foreach my $ff (keys %{$s->{-meta}->{$f}->{-fields}}) {
$s->{-meta}->{$f}->{-fldids}->{$s->{-meta}->{$f}->{-fields}->{$ff}->{fieldId}}
=$s->{-meta}->{$f}->{-fields}->{$ff}
}
lib/ARSObject.pm view on Meta::CPAN
$s->{-metadn}->{$s->{-metaid}->{$id}->{fieldName}} =$s->{-metaid}->{$id}
if $s->{-metaid}->{$id}->{fieldName}
&& !$s->{-metadn}->{$s->{-metaid}->{$id}->{fieldName}};
}
}
# print $s->cpcon($s->dsdump($s->{-metaid})), "\n"; exit(0);
}
}
sub arsmetamin { # Minimal ARS metadata ('-meta-min' varfile)
my $s =shift; # refresh after 'arsmeta'/'connect'
$s->set(@_); # load instead of 'arsmeta'/'connect'
local $s->{-cmd} =($s->{-cmd} ? $s->{-cmd} .': ' : '')
.($s->{-schgen} ? "dumper('" .$s->vfname('meta-min') ."')" : 'arsmetamin()');
if (ref($s->{-schgen})
|| !$s->{-schgen}
|| ($s->{-schgen} && ($s->{-schgen} >1))
|| (!-e $s->vfname('-meta-min'))
) {
$s->arsmeta() if !$s->{-meta} ||!scalar(%{$s->{-meta}});
my $fvs =[stat $s->vfname('-meta-min')]->[9] ||0;
$fvs =0 if ($s->{-schgen} && (ref($s->{-schgen}) || ($s->{-schgen} >2)));
$fvs =0 if $fvs && ($fvs <([stat $s->vfname('-meta')]->[9]||0));
$fvs =0 if $fvs && ($fvs <([stat ($^O eq 'MSWin32' ? scalar(Win32::GetFullPathName($0)) : $0)]->[9]||0));
if (!$fvs) {
$s->{'-meta-min'} ={};
foreach my $f (keys %{$s->{-meta}}) {
foreach my $ff (keys %{$s->{-meta}->{$f}->{-fields}}) {
my $e =$s->{-meta}->{$f}->{-fields}->{$ff};
next if (!$e->{dataType}
|| ($e->{dataType} ne 'time'))
&& (!$e->{'limit'}
|| !$e->{'limit'}->{'enumLimits'}
|| !($e->{'limit'}->{'enumLimits'}->{'regularList'} ||$e->{'limit'}->{'enumLimits'}->{'customList'}));
$s->{'-meta-min'}->{$f} ={} if !$s->{'-meta-min'}->{$f};
$s->{'-meta-min'}->{$f}->{-fields} ={} if !$s->{'-meta-min'}->{$f}->{-fields};
$e ={%$e};
delete @$e{'owner','lastChanged', 'timestamp'};
$s->{'-meta-min'}->{$f}->{-fields}->{$ff} ={%$e};
}
}
lib/ARSObject.pm view on Meta::CPAN
=values %{$fs->{-fields}->{$ff}}};
}
}
$s->arsmetaix()
}
delete $s->{'-meta-min'};
$s;
}
sub arsmetasql { # SQL ARS metadata ('-meta-sql' varfile)
my $s =shift; # refresh after 'arsmeta'/'connect'
$s->set(@_); # !!! 'enum' texts
local $s->{-cmd} =($s->{-cmd} ? $s->{-cmd} .': ' : '')
.($s->{-schgen} ? "dumper('" .$s->vfname('meta-sql') ."')" : 'arsmetasql()');
if (ref($s->{-schgen})
|| !$s->{-schgen}
|| ($s->{-schgen} && ($s->{-schgen} >1))
|| (!-e $s->vfname('-meta-sql'))
) {
$s->arsmeta() if !$s->{-meta} ||!scalar(%{$s->{-meta}});
lib/ARSObject.pm view on Meta::CPAN
$fvs =0 if ($s->{-schgen} && (ref($s->{-schgen}) || ($s->{-schgen} >2)));
$fvs =0 if $fvs && ($fvs <([stat $s->vfname('-meta')]->[9]||0));
$fvs =0 if $fvs && ($fvs <([stat ($^O eq 'MSWin32' ? scalar(Win32::GetFullPathName($0)) : $0)]->[9]||0));
if (!$fvs) {
$s->vfload('-meta-sql') if $s->{-schgen} && -e $s->vfname('-meta-sql');
$s->{'-meta-sql'} ={} if !$s->{'-meta-sql'};
foreach my $f ($s->{-schema} ? @{$s->{-schema}} : sort keys %{$s->{-meta}}) {
$s->sqlname($f);
foreach my $ff (sort keys %{$s->{-meta}->{$f}->{-fields}}) {
$s->sqlname($f,$ff,1);
if ($s->{-meta}->{$f}->{-fields}->{$ff}->{dataType} eq 'enum') {
# $s->sqlname($f,'_str_' .$ff,1);
# $s->{'-meta-sql'}->{$s->sqlname($f)}->{-cols}->{$s->sqlname($f,'_str_' .$ff)}->{TYPE_NAME} ='varchar';
}
}
foreach my $ff ('_arsobject_insert', '_arsobject_update', '_arsobject_delete') {
$s->sqlname($f,$ff,1);
$s->{'-meta-sql'}->{$s->sqlname($f)}->{-cols}->{$s->sqlname($f,$ff)}->{TYPE_NAME} ='int';
}
}
$s->vfstore('-meta-sql') if $s->{-schgen} && ($s->{-schgen} eq '1' ? !-e $s->vfname('-meta-sql') : 1);
lib/ARSObject.pm view on Meta::CPAN
? &{$s->{-sqlname}($s, $ff)}
: sqlnesc($s, $ff);
return($tc) if !$tc;
while ($s->{'-meta-sql'}->{$tn}->{-cols}->{$tc} && ($s->{'-meta-sql'}->{$tn}->{-cols}->{$tc}->{fieldName} ne $ff)) {
$tc =$s->{-sqlninc} ? &{$s->{-sqlninc}}($s, $tc) : sqlninc($s, $tc);
}
if ($fu ||!$s->{'-meta-sql'}->{$tn}->{-cols}->{$tc}) {
my $flh =$s->{-meta}->{$f}->{-fields}->{$ff}->{limit};
my $tch ={COLUMN_NAME => $tc
, 'fieldName'=>$ff
, 'dataType' => $ffh->{dataType}
, 'timestamp'=>$s->{'-meta-sql'}->{$tn}->{-cols}->{$tc}
&& $s->{'-meta-sql'}->{$tn}->{-cols}->{$tc}->{'timestamp'}
|| time()
, $ffh && $ffh->{fieldId}
? ('fieldId' => $ffh->{fieldId})
: ()
, !$ffh ||!$ffh->{dataType}
? ()
: $ffh->{dataType} eq 'integer'
? (TYPE_NAME => 'int')
: $ffh->{dataType} eq 'real'
? (TYPE_NAME => 'float')
: $ffh->{dataType} eq 'decimal'
? (TYPE_NAME => $ffh->{dataType}
, $flh
? ($flh->{precision} ? (DECIMAL_DIGITS => $flh->{precision}) : ()
,$flh->{rangeHigh} ? (COLUMN_SIZE => length($flh->{rangeHigh})) : ()
)
: ()
)
: $ffh->{dataType} eq 'char'
&& (!$flh || !$flh->{maxLength} || ($flh->{maxLength} >255))
? (TYPE_NAME => 'text')
: 0 && ($ffh->{dataType} eq 'char') && $ffh->{indexUnique}
? (TYPE_NAME => 'char'
, $flh && $flh->{maxLength}
? (COLUMN_SIZE => $flh->{maxLength})
: ()
)
: $ffh->{dataType} eq 'char'
? (TYPE_NAME=>'varchar' # $ffh->{dataType}
, $flh && $flh->{maxLength}
? (COLUMN_SIZE => $flh->{maxLength})
: ()
)
: $ffh->{dataType} eq 'diary'
? (TYPE_NAME => 'text')
: $ffh->{dataType} eq 'time'
? (TYPE_NAME => 'datetime' # !'int'
#,COLUMN_SIZE=>19,DECIMAL_DIGITS=>0
)
: $ffh->{dataType} eq 'enum'
? (TYPE_NAME => 'int')
: ()
, $ffh && $ffh->{fieldId}
&& (($ffh->{fieldId} =~/^(?:1)$/) || $ffh->{indexUnique})
? (IS_PK => $ffh->{fieldId})
: ()
, $ffh && $ffh->{fieldMap}
&& $ffh->{fieldMap}->{fieldType}
&& ($ffh->{fieldMap}->{fieldType} ==2)
&& $ffh->{fieldMap}->{join}
lib/ARSObject.pm view on Meta::CPAN
}
sub schlbls { # Enum field {values => labels}
# (schema, fieldId) -> {value=>label,...}
my($s,$f,$ff) =@_;
$ff =ref($ff) ? $ff
: !$s->{-meta} || !$s->{-meta}->{$f} ? return(undef)
: $ff =~/^\d+$/ ? $s->{-meta}->{$f}->{-fldids}->{$ff}
: $s->{-meta}->{$f}->{-fields}->{$ff};
if ($ff && !$ff->{-hashOut} && ($ff->{dataType} eq 'enum')) {
my $et =ref($ff->{'limit'}->{'enumLimits'}) eq 'ARRAY'
? $ff->{'limit'}->{'enumLimits'}
: exists $ff->{'limit'}->{'enumLimits'}->{'regularList'}
? $ff->{'limit'}->{'enumLimits'}->{'regularList'}
: exists $ff->{'limit'}->{'enumLimits'}->{'customList'}
? $ff->{'limit'}->{'enumLimits'}->{'customList'}
: undef;
if (!$et) {}
elsif (!ref($et->[0])) {
$ff->{-hashOut} ={map {($_ => $et->[$_])} (0..$#$et)}
lib/ARSObject.pm view on Meta::CPAN
sub schvals { # Enum field [values]
# (schema, fieldId) -> [value,...]
my($s,$f,$ff) =@_;
$ff =ref($ff) ? $ff
: !$s->{-meta} || !$s->{-meta}->{$f} ? return(undef)
: $ff =~/^\d+$/ ? $s->{-meta}->{$f}->{-fldids}->{$ff}
: $s->{-meta}->{$f}->{-fields}->{$ff};
if ($ff && !$ff->{-listVals} && ($ff->{dataType} eq 'enum')) {
my $et =ref($ff->{'limit'}->{'enumLimits'}) eq 'ARRAY'
? $ff->{'limit'}->{'enumLimits'}
: exists $ff->{'limit'}->{'enumLimits'}->{'regularList'}
? $ff->{'limit'}->{'enumLimits'}->{'regularList'}
: exists $ff->{'limit'}->{'enumLimits'}->{'customList'}
? $ff->{'limit'}->{'enumLimits'}->{'customList'}
: undef;
if (!$et) {}
elsif (!ref($et->[0])) {
$ff->{-listVals} =[0..$#$et]
lib/ARSObject.pm view on Meta::CPAN
$v =$1
}
elsif ($ff->{-hashOut}) {
if (exists($ff->{-hashOut}->{$v})) {
$v =$ff->{-hashOut}->{$v}
}
else {
# return(&{$s->{-die}}($s->efmt('Could not transate value',$s->{-cmd},undef,'strOut',$f,$ff->{fieldName},$v)))
}
}
elsif ($ff->{dataType} eq 'enum') {
schlbls(@_);
$v =strOut(@_) if $ff->{-hashOut};
}
elsif ($ff->{dataType} eq 'time') {
$v =strtime($s,$v)
}
$v
}
sub strIn { # Convert input field value to internal, using '-meta'
# (schema, fieldId, fieldValue) -> fieldValue
my($s,$f,$ff,$v) =@_;
$ff =ref($ff) ? $ff : $ff =~/^\d+$/ ? $s->{-meta}->{$f}->{-fldids}->{$ff} : $s->{-meta}->{$f}->{-fields}->{$ff};
lib/ARSObject.pm view on Meta::CPAN
$v =$1
}
elsif ($ff->{-hashIn}) {
if (exists($ff->{-hashIn}->{$v})) {
$v =$ff->{-hashIn}->{$v};
}
else {
return(&{$s->{-die}}($s->efmt('Could not transate value',$s->{-cmd},undef,'strIn',$f,$ff->{fieldName},$v)))
}
}
elsif ($ff->{dataType} eq 'enum') {
my $et = ref($ff->{'limit'}->{'enumLimits'}) eq 'ARRAY'
? $ff->{'limit'}->{'enumLimits'}
: exists $ff->{'limit'}->{'enumLimits'}->{'regularList'}
? $ff->{'limit'}->{'enumLimits'}->{'regularList'}
: exists $ff->{'limit'}->{'enumLimits'}->{'customList'}
? $ff->{'limit'}->{'enumLimits'}->{'customList'}
: undef;
if (!$et) {}
elsif (!ref($et->[0])) {
$ff->{-hashIn} ={map {($et->[$_] => $_)} (0..$#$et)};
lib/ARSObject.pm view on Meta::CPAN
elsif ((ref($et->[0]) eq 'HASH') && defined($et->[0]->{itemNumber})) {
$ff->{-hashIn} ={map {($et->[$_]->{itemName} => $et->[$_]->{itemNumber})} (0..$#$et)};
$v =strIn(@_);
}
else {
$et =undef
}
return(&{$s->{-die}}($s->efmt('Could not transate value',$s->{-cmd},undef,'strIn',$f,$ff->{fieldName},$v)))
if $et && ($v !~/^\d+$/);
}
elsif ($ff->{dataType} eq 'time') {
$v =timestr($s,$v);
}
$v
}
sub lsflds { # List fields from '-meta'
# (additional field options)
my ($s, @a) =@_;
@a =('fieldLblc') if !@a;
unshift @a, 'fieldName', 'fieldId', 'dataType', 'option', 'createMode';
map { my $f =$_;
$f =~/^-/
? ()
: map { my $ff =$s->{-meta}->{$f}->{-fields}->{$_};
join("\t", $f
#, $ff->{option} && ($ff->{option} == 4) ? 'ro' : ()
, (map { $_ eq 'fieldLblc'
? join('; '
, map {$ff->{$_} ? $ff->{$_} : ()
} $ff->{$_} ? ('fieldLblc') : ('fieldLbl', 'fieldLbll'), 'fieldLbv', 'fieldLbvl', 'helpText')
lib/ARSObject.pm view on Meta::CPAN
my %a =@_;
my $f =$a{-schema} ||$a{-form} ||$a{-from};
my $c =$a{-for} ||$a{-foreach};
if ($a{-fields} && !ref($a{-fields})) {
my $q ='trim|control|table|column|page';
$q .= '|currency|attach' if $a{-fields} =~/^-\$/;
$q .= '|attach' if $a{-fields} =~/^-f/;
$a{-fields} =
[map { my $ff =$s->{-meta}->{$f}->{-fields}->{$_};
!$ff->{dataType} || !$ff->{fieldId}
|| ($ff->{dataType} =~/^($q)/)
|| ($ff->{fieldId} eq '15') # 'Status-History'
# ars_GetListEntryWithFields() -> [ERROR] (ORA-00904: "C15": invalid identifier) (ARERR #552)
|| (!$a{-xfields} ? 0 : ref($a{-xfields}) eq 'CODE' ? &{$a{-xfields}}($s, $ff) : grep {($_ eq $ff->{fieldId}) || ($_ eq $ff->{fieldName})} @{$a{-xfields}})
? ()
: ($ff->{fieldId})
} sort keys %{$s->{-meta}->{$f}->{-fields}}]
}
$a{-fetch} =1 if $a{-fields} && !ref($a{-fields});
delete $a{-fields} if $a{-fetch};
lib/ARSObject.pm view on Meta::CPAN
my $r =ARS::ars_DeleteEntry($s->{-ctrl}, $f, $id);
return(&{$s->{-die}}($s->efmt($ARS::ars_errstr
,"entryDel(-form=>'$f',-id=>'$id')")))
if !$r && $ARS::ars_errstr;
$id
}
sub entryBLOB { # BLOB field retrieve/update
# (-form=>form, -id=>entryId, -field=>fieldId|fieldName
# ,?-set=>data
# ,?-file=>filePath, ?-set=>boolean
my ($s, %a) =@_;
my $f =$a{-schema} ||$a{-form} ||$a{-from} ||$a{-into};
my $eu =!$a{-file} ? exists($a{-set}) : exists($a{-set}) ? $a{-set} : $a{-into};
if ($eu) {
return($s->entryUpd(-form=>$f, -id=>$a{-id}
, exists($a{-echo}) ? (-echo=>$a{-echo}) : ()
, $a{-field}
, {$a{-file}
? ('file'=>$a{-file}, 'size'=> -s $a{-file})
lib/ARSObject.pm view on Meta::CPAN
}
}
sub dbi { # DBI connection object
return($_[0]->{-dbi}) if $_[0]->{-dbi};
dbiconnect(@_)
}
sub dbiconnect {# DBI connect to any database
# (-dbiconnect=>[]) -> dbi object
set(@_);
set($_[0],-die=>'Carp') if !$_[0]->{-die};
print $_[0]->cpcon("dbiconnect()\n")
if $_[0]->{-echo};
eval('use DBI; 1') ||return(&{$_[0]->{-die}}($_[0]->efmt('No DBI')));
$_[0]->{-dbi} =DBI->connect(ref($_[0]->{-dbiconnect}) ? @{$_[0]->{-dbiconnect}} : $_[0]->{-dbiconnect})
|| &{$_[0]->{-die}}($_[0]->efmt(DBI->errstr,undef,undef,'dbiconnect') ."\n");
}
lib/ARSObject.pm view on Meta::CPAN
sub dbitypespc { # DBI column type spec
my ($s, $d) =@_;
($d->{'TYPE_NAME'} ||'unknown')
.($d->{'COLUMN_SIZE'}
? ' (' .join(',', map {defined($d->{$_}) ? $d->{$_} : ()
} 'COLUMN_SIZE', 'DECIMAL_DIGITS') .')'
: '')
}
sub dbidsmetasync { # DBI datastore - sync meta with 'arsmetasql'
my ($s, %arg) =@_; # (-echo)
return(undef) if !$s->{'-meta-sql'};
my $dbt ={map {!$_
? ()
: $_ =~/\."*([^."]+)"*$/
? (lc($1) => 1)
: (lc($_) => 1)
} $s->dbitables()};
foreach my $tbl (sort keys %{$s->{'-meta-sql'}}) {
my @sql;
lib/ARSObject.pm view on Meta::CPAN
foreach my $r (@sql) {
print "$r;\n" if exists($arg{-echo}) ? $arg{-echo} : $s->{-echo};
$s->dbi()->do($r)
|| &{$s->{-die}}($s->efmt($s->{-dbi}->errstr,$r,undef,'dbidsmetasync'));
}
}
$s;
}
sub dbidsrpl { # DBI datastore - load data from ARS
my ($s, %arg) =@_;
$arg{-form} =$arg{-from} ||$arg{-schema} if !$arg{-form};
$arg{-query} =$arg{-where} ||$arg{-qual} if !$arg{-query};
$arg{-filter}=undef if !$arg{-filter};
$arg{-lim_rf}=300 if !$arg{-lim_rf};
$arg{-lim_or}=40 if !$arg{-lim_or};
$arg{-fields}='*' if !$arg{-fields};
# $arg{-echo}=0;
# $arg{-ckpush}=1; # check db pushes into ARS (_arsobject_insert, _arsobject_update, _arsobject_delete)
# $arg{-ckdel}=0; # check ARS deletes into db
lib/ARSObject.pm view on Meta::CPAN
my $sql ='';
$rd =$s->dbiquery($fpksql .$s->{-dbi}->quote($r->{$fpk->{fieldName}}))->fetchrow_hashref();
my $ru;
foreach my $f (@flds) {
next if !$f->{fieldName} || !$f->{COLUMN_NAME} || !$f->{TYPE_NAME}
|| !exists($r->{$f->{fieldName}});
$rw->{$f->{fieldName}} =!defined($r->{$f->{fieldName}})
? $r->{$f->{fieldName}}
: $f->{TYPE_NAME} eq 'datetime'
? strtime($s, $r->{$f->{fieldName}})
: ($f->{dataType} =~/^(?:char)$/) && $f->{COLUMN_SIZE}
? substr($r->{$f->{fieldName}}, 0, $f->{COLUMN_SIZE_DB} ||$f->{COLUMN_SIZE})
: $r->{$f->{fieldName}};
$rd->{$f->{COLUMN_NAME}} =$1
if $rd
&& defined($rd->{$f->{COLUMN_NAME}})
&& ($f->{TYPE_NAME} =~/^(?:datetime|float)$/)
&& ($rd->{$f->{COLUMN_NAME}}=~/^(.+)\.0+$/);
$rd->{$f->{COLUMN_NAME}} =defined($rw->{$f->{fieldName}}) && ($rw->{$f->{fieldName}} =~/\.(\d+)$/)
? sprintf('%.' .length($1) .'f', $rd->{$f->{COLUMN_NAME}})
: $rd->{$f->{COLUMN_NAME}} =~/^(.+)\.0+$/
? $1
: $rd->{$f->{COLUMN_NAME}}
if $rd
&& defined($rd->{$f->{COLUMN_NAME}})
&& ($f->{TYPE_NAME} eq 'float');
$rd->{$f->{COLUMN_NAME}} =substr($rd->{$f->{COLUMN_NAME}}, 0, $f->{COLUMN_SIZE_DB} ||$f->{COLUMN_SIZE})
if $rd
&& defined($rd->{$f->{COLUMN_NAME}})
&& ($f->{dataType} =~/^(?:char)$/) && $f->{COLUMN_SIZE};
$ru =1 if $rd
&& (defined($rd->{$f->{COLUMN_NAME}})
? !defined($rw->{$f->{fieldName}})
|| ($rd->{$f->{COLUMN_NAME}} ne $rw->{$f->{fieldName}})
: defined($rw->{$f->{fieldName}}));
}
if (!$rd) {
next if $arg{-filter}
&& !&{$arg{-filter}}($s,\%arg,$s->{'-meta-sql'}->{$tbl},$rw,$rd);
$sql ='INSERT INTO ' .$tbc .' ('
lib/ARSObject.pm view on Meta::CPAN
my $n= $s->{-dbi}->do($sql)
|| &{$s->{-die}}($s->efmt($s->{-dbi}->errstr,$sql,undef,'dbidsrpl',$arg{-form}));
$cd +=$n;
}
}
join(', ', map {$_ ? $_ : ()} $ci && "new $ci", $cu && "upd $cu", $cd && "del $cd")
||'up-to-date'
}
sub dbidsquery { # DBI datastore - query data alike ARS
my ($s, %arg) =@_;
# -form => ARS form || -from => sql table name
# -fields=> ARS fields || -select=>sql select list
# -query=> ARS query || -where => sql where
# -order =>
# -filter=> undef
# -undefs=>1
# -strFields=>1|0
my $m =$s->{'-meta-sql'}->{$s->sqlname($arg{-form})};
my $sql =join(' ', 'SELECT'
lib/ARSObject.pm view on Meta::CPAN
local $s->{-strFields} =defined($arg{-strFields}) ? $arg{-strFields} : $s->{-strFields};
my ($r, $r1, @r);
while ($r =$h->fetchrow_hashref()) {
$r1 ={map { $xu && !defined($r->{$_})
? ()
: $m->{-cols}->{$_} && $m->{-cols}->{$_}->{fieldName} && $m->{-cols}->{$_}->{fieldId}
? ($m->{-cols}->{$_}->{fieldName}
=>
(!defined($r->{$_})
? $r->{$_}
: $ys && ($m->{-cols}->{$_}->{dataType} eq 'enum')
? $s->strOut($arg{-form}, $m->{-cols}->{$_}->{fieldId}, $r->{$_})
: ($m->{-cols}->{$_}->{TYPE_NAME} =~/^(?:datetime|float)$/) && ($r->{$_} =~/^(.+)\.0+$/)
? $1
: $r->{$_}))
: $yc
? ($_ => $r->{$_})
: ()
} keys %$r};
next if $arg{-filter} && !&{$arg{-filter}}($s,$r1);
push @r, $r1;
}
@r
}
sub dbidsqq { # DBI datastore - quote/parse condition to SQL names
my ($s,$sf,$mh) =@_; # (self, query string, default sql metadata)
if (0) {
my $q =substr($s->{-dbi}->quote_identifier(' '),0,1);
$sf =~s/$q([^$q]+)$q\.$q([^$q]+)$q/!$s->{'-meta-sql'}->{-forms}->{$1} ? "?1$q$1${q}.$q$2$q" : $s->{'-meta-sql'}->{$s->{'-meta-sql'}->{-forms}->{$1}}->{-fields}->{$2} ? $s->{-dbi}->quote_identifier($s->{'-meta-sql'}->{-forms}->{$1}) .'.' .$s->{-dbi}-...
$sf =~s/$q([^$q]+)$q/$s->{'-meta-sql'}->{-forms}->{$1} ? ($s->{-sqlschema} ? $s->{-dbi}->quote_identifier($s->{-sqlschema}) .'.' : '') .$s->{-dbi}->quote_identifier($s->{'-meta-sql'}->{-forms}->{$1}) : $mh->{-fields}->{$1} ? $s->{-dbi}->quote_identi...
return($sf);
}
my $qs =$s->{-dbi}->quote('w') =~/^([^w]+)w/ ? $1 : "'";
my $qi =$s->{-dbi}->quote_identifier('w') =~/^([^w]+)w/ ? $1 : '"';
my $qsq=$s->{-dbi}->quote("'w") =~/^([^w]+)w/ ? $1 : "''";
my $qiq=$s->{-dbi}->quote_identifier('"w') =~/^([^w]+)w/ ? $1 : '""';
lib/ARSObject.pm view on Meta::CPAN
sub smtp { # SMTP connection object
return($_[0]->{-smtp}) if $_[0]->{-smtp};
smtpconnect(@_)
}
sub smtpsend { # SMTP mail msg send
# -from||-sender, -to||-recipient,
# -data|| -subject + (-text || -html)
my ($s, %a) =@_;
return(&{$s->{-die}}("SMTP host not defined"))
if !$s->{-smtphost};
local $s->{-smtpdomain} =$s->{-smtpdomain}
|| ($s->{-smtphost} && $s->smtp(sub{$_[1]->domain()}))
|| 'nothing.net';
$a{-from} =$a{-from} ||$a{-sender} ||$ENV{REMOTE_USER} ||$ENV{USERNAME};
$a{-from} =&{$a{-from}}($s,\%a) if ref($a{-from}) eq 'CODE';
$a{-to} =&{$a{-to}}($s,\%a) if ref($a{-to}) eq 'CODE';
$a{-to} =[grep {$_} split /\s*[,;]\s*/, ($a{-to} =~/^\s*(.*)\s*$/ ? $1 : $a{-to})]
if $a{-to} && !ref($a{-to}) && ($a{-to} =~/[,;]/);
$a{-sender} =$a{-sender} ||$a{-from};
$a{-recipient} =$a{-recipient} ||$a{-to};
$a{-recipient} =&{$a{-recipient}}($s,\%a) if ref($a{-recipient}) eq 'CODE';
$a{-recipient} =[grep {$_} split /\s*[,;]\s*/, ($a{-recipient} =~/^\s*(.*)\s*$/ ? $1 : $a{-recipient})]
if $a{-recipient} && ref($a{-recipient}) && ($a{-recipient} =~/[,;]/);
return(&{$s->{-die}}("SMTP e-mail recipients not defined"))
if !$a{-recipient};
if (!defined($a{-data})) {
my $koi =(($a{-charset}||$s->charset()||'') =~/1251/);
$a{-subject} = ref($a{-subject}) eq 'CODE'
? &{$a{-subject}}($s,\%a)
: 'ARSObject'
if ref($a{-subject}) ||!defined($a{-subject});
$a{-data} ='';
$a{-data} .='From: ' .($koi ? $s->cptran('ansi','koi',$a{-from})
: $a{-from})
."\cM\cJ";
$a{-data} .='Subject: '
.($koi
? $s->cptran('ansi','koi',$a{-subject})
: $a{-subject}) ."\cM\cJ";
$a{-data} .='To: '
.($koi
? $s->cptran('ansi','koi', ref($a{-to}) ? join(', ',@{$a{-to}}) : $a{-to})
: (ref($a{-to}) ? join(', ',@{$a{-to}}) : $a{-to}))
."\cM\cJ"
if $a{-to};
foreach my $k (keys %a) {
next if $k =~/^-(data|subject|html|text|from|to|sender|recipient)$/;
next if !defined($a{$k});
my $n =$k =~/^-(.+)/ ? ucfirst($1) .':' : $k;
$a{-data} .=$n .' ' .$a{$k} ."\cM\cJ";
}
$a{-data} .="MIME-Version: 1.0\cM\cJ";
$a{-data} .='Content-type: ' .($a{-html} ? 'text/html' : 'text/plain')
.'; charset=' .($a{-charset}||$s->charset())
."\cM\cJ";
$a{-data} .='Content-Transfer-Encoding: ' .($a{-encoding} ||'8bit') ."\cM\cJ";
$a{-data} .="\cM\cJ";
$a{-data} .=$a{-html} ||$a{-text} ||'';
}
local $^W=undef;
$s->smtp->mail($a{-sender} =~/<\s*([^<>]+)\s*>/ ? $1 : $a{-sender})
||return(&{$s->{-die}}("SMTP sender \'" .$a{-sender} ."' -> " .($s->smtp->message()||'?')));
$s->smtp->to(ref($a{-recipient})
? (map { !$_ ? () : /<\s*([^<>]+)\s*>/ ? $1 : $_ } @{$a{-recipient}})
: $a{-recipient}, {'SkipBad'=>1}) # , {'SkipBad'=>1}
|| return(&{$s->{-die}}("SMTP recipient \'"
.(ref($a{-recipient}) ? join(', ', (map { !$_ ? () : /<\s*([^<>]+)\s*>/ ? $1 : $_ } @{$a{-recipient}})) : $a{-recipient}) ."' -> " .($s->smtp->message()||'?')));
$s->smtp->data($a{-data})
||return(&{$s->{-die}}("SMTP data '" .$a{-data} ."' -> " .($s->smtp->message()||'?')));
my $r =$s->smtp->dataend()
||return(&{$s->{-die}}("SMTP dataend -> " .($s->smtp->message()||'?')));
$r ||1;
}
sub soon { # Periodical execution of this script
# (minutes ||sub{}, ?log file, ?run command, ?soon command)
# minutes: undef - clear sched, run once || sub{} -> number
# log file: empty || full file name || var file name
# run command: empty || 'command line' || [command line] || sub{}
# soon command: empty || 'command line' || [command line] || []
lib/ARSObject.pm view on Meta::CPAN
print("$cmd # $l\n");
$s->fstore(">>$lf", $s->strtime() ."\t$$\t$cmd # $l\n")
if $lf;
system($cmd);
}
}
1
}
sub cfpinit { # Field Player: init data structures
my ($s) =@_; # (self) -> self
$s->{-fphc} ={};
$s->{-fphd} ={};
my $dh ={};
my $dp =undef;
my $ah ={};
my $ak;
my $bf =undef;
foreach my $f (@{$s->{-fpl}}) {
if (ref($f) && $f->{-key} && $f->{-namecgi}) {
lib/ARSObject.pm view on Meta::CPAN
elsif ($ae =~/^(?:vfentry|entry)$/ && ref($s->{-fpbv})) {
$r =shift @{$s->{-fpbv}} if scalar(@{$s->{-fpbv}});
$r ={} if !$r;
}
elsif ($ae eq 'vfentry') { # -preact
my $fs =$f->{-vfname} ||$af->{-vfname};
my $fn =undef;
my $fv =undef;
if ($frk && $fs && ($fn =$frk->{-namedb}) && defined($fv=cfpv($s, $frk->{-master}))) {
$s->{-fpbv} =$f->{-namedb}
? $s->vfdata($fs, sub{defined($_->{$fn}) && ($_->{$fn} eq $fv)})
: [];
$r =shift @{$s->{-fpbv}} if $s->{-fpbv} && scalar(@{$s->{-fpbv}});
$r ={} if !$r;
}
elsif ($fs) {
$r =undef;
if (defined($fv=cfpv($s, $f))) {
$fn =$f->{-namedb}
}
elsif ($af->{-namedb} && ($fv =cfpv($s, $af))) {
$fn =$af->{-namedb};
}
elsif ($fn =cfpnd($s, cfpv($s, $af))) {
$fv =cfpv($s, $fn)
}
if ($fn && defined($fv)) {
$r =undef;
my $fa =$s->vfdata($fs);
foreach my $e (@$fa) {
next if !defined($e->{$fn}) || ($e->{$fn} ne $fv);
$r =$e;
last
}
$@="Not found '$fn'=\"$fv\""
if !$r;
}
else {
$@ =$fn
lib/ARSObject.pm view on Meta::CPAN
elsif (($af->{-vfclear} || $f->{-vfclear}) && $s->{"${fs}-calc"}) {
$s->vfclear($fs);
}
elsif (($af->{-vfrenew} || $f->{-vfrenew}) && $s->{"${fs}-store"}) {
eval{$s->vfclear($fs); $s->vfrenew($fs)}
}
elsif ($af->{-vfedit} || $f->{-vfedit}) {
my $fn =$f->{-namedb} ||$af->{-namedb};
my $ft =defined($f->{-vftran}) ? $f->{-vftran} : $af->{-vftran};
my $fv =cfpv($s, $f);
my $fa =$s->vfdata($fs);
push @$fa, {$f->{-namedb} ? ($f->{-namedb}=>$r) : ()
,map { &$ffc($s, $_) ||(exists($_->{-vfstore}) && !$_->{-vfstore})
? ()
: ($_->{-namedb} => &$fvu($s, $_, $ft))
} cfpused($s)};
$s->vfstore($fs);
$s->vfclear($fs);
}
}
elsif ($ae eq 'entryUpd') { # -action
lib/ARSObject.pm view on Meta::CPAN
elsif (($af->{-vfclear} || $f->{-vfclear}) && $s->{"${fs}-calc"}) {
$s->vfclear($fs);
}
elsif (($af->{-vfrenew} || $f->{-vfrenew}) && $s->{"${fs}-store"}) {
eval{$s->vfclear($fs); $s->vfrenew($fs)}
}
elsif ($af->{-vfedit} || $f->{-vfedit}) {
my $fn =$f->{-namedb} ||$af->{-namedb};
my $ft =defined($f->{-vftran}) ? $f->{-vftran} : $af->{-vftran};
my $fv =cfpv($s, $f);
my $fa =$s->vfdata($fs);
foreach my $e (@$fa) {
next if !defined($e->{$fn}) || ($e->{$fn} ne $fv);
foreach my $f1 (cfpused($s)) {
next if &$ffc($s, $f1) ||(exists($f1->{-vfstore}) && !$f1->{-vfstore});
$e->{$f1->{-namedb}} =&$fvu($s, $f1, $ft);
}
last;
}
$s->vfstore($fs);
$s->vfclear($fs);
lib/ARSObject.pm view on Meta::CPAN
}
elsif (($af->{-vfclear} || $f->{-vfclear}) && $s->{"${fs}-calc"}) {
$s->vfclear($fs);
}
elsif (($af->{-vfrenew} || $f->{-vfrenew}) && $s->{"${fs}-store"}) {
eval{$s->vfclear($fs); $s->vfrenew($fs)}
}
elsif ($af->{-vfedit} || $f->{-vfedit}) {
my $fn =$f->{-namedb} ||$af->{-namedb};
my $fv =cfpv($s, $f);
my $fa =$s->vfdata($fs);
my ($i,$j) =(0, undef);
foreach my $e (@$fa) {
if (defined($e->{$fn}) && ($e->{$fn} eq $fv)) {
$j =$i;
last;
}
$i++
}
splice(@$fa, $i, 1);
$s->vfstore($fs);
lib/ARSObject.pod view on Meta::CPAN
}
);
print $s->dsdump($hac);
=head1 DESCRIPTION
This module is intended for capable scripts above L<ARS|ARS> module
(L<../../ARSPerl/index.html>).
It caches metadata alike L<Remedy::ARSTools|Remedy/ARSTools>,
but uses L<Data::Dumper|Data/Dumper> or L<Storable|Storable> module.
And metadata model is directly given from ARS::ars_GetFieldTable()/ARS::ars_GetField(),
unlike L<ARSOOForm|ARSOOForm> and L<Remedy::ARSTools|Remedy/ARSTools>.
And additional description level (C<-metadn>/C<-metaid>) added to unify field names
and extend conversion capabilities of field values.
Field names and values are translated (C<-strFields>/C<strIn>/C<strOut>)
as possible.
C<query>() method supports iterator sub{} and uses ARS::ars_GetListEntry(),
ARS::ars_GetListEntryWithFields(), ARS::ars_GetEntry() calls
as appropriate with parameters given.
C<entry>(), C<entryIns>(), C<entryUpd>(), C<entryDel>() methods
are usual to manipulate records.
C<entryNew>() method may be used to form new record hash with default values for C<entryIns>().
C<entryDif>() method may be used to minimise data for C<entryUpd>().
C<AUTOLOAD>() method is to call 'ARS::ars_XXX' functions as methods.
Special processing added for 'HPD:Help Desk' ITSM Suite form.
C<Variable files> may be used to cache any data.
Misc C<Utility Methods> intended for strings, dates, data structures.
C<Utility Objects> added to simplify and unify access to
L<DBI|DBI>, L<CGI|CGI>, L<Net::SMTP|Net/SMTP> modules.
=back
=head1 CLASSIFICATION
lib/ARSObject.pod view on Meta::CPAN
=item Connection
C<connect>(C<-srv> => server, C<-usr> => name, C<-pswd> => password, C<-lang> => language);
C<-ctrl>
C<dbiconnect>(C<-dbiconnect>); C<-dbi>
=item Metadata
C<connect>; C<arsmeta>, C<arsmetamin>; C<schema>,...; C<lsflds>;
C<-schema>, C<-meta>/C<-meta-min>/C<-meta-sql>, C<-metax>, C<-metadn>, C<-metaid>, C<-schgen>, C<-schfdo>, C<-strFields>;
C<Variable files>
=item Variable files
C<-vfbase>, C<-storable>;
C<vfname>, C<vfload>, C<vfstore>, C<vfclear>, C<vfdata>, C<vfhash>, C<vfdistinct>
=item ARS methods
C<connect>, C<query>, C<entry>, C<entryNew>, C<entryIns>, C<entryUpd>, C<entryDel>, C<entryBLOB>, C<AUTOLOAD>;
C<-strFields>, C<strIn>, C<strOut>;
C<arsquot>;
lib/ARSObject.pod view on Meta::CPAN
(C<CGI Form Presenter - Field Definitions>)
db form name, may be defined as a
special C<-fpl> entry before field definitions.
=item -key
=> => not exists || boolean
(C<CGI Form Presenter - Field Definitions>)
Key database field?
=item -labels
=> not exists || {value=>label,..} || {value=>{{-label=>label, field=>value,..},..}
|| sub{}({self},{field},$_=value) -> {value=>label,..}
(C<CGI Form Presenter - Field Definitions>)
Labels for the drop-down list box field.
If no C<-values>, this will be generated automatically.
lib/ARSObject.pod view on Meta::CPAN
(C<CGI Form Presenter - Field Definitions>)
Name of the field containg value for this field.
=item -metadb
=> not exists || 'ARS field name'
(C<CGI Form Presenter - Field Definitions>)
ARS field name to be used for field metadata:
C<-name>, C<-namelbl>, C<-labels>, C<-value>, etc.
=item -name
=> not exists || 'common field name'
=item -namecgi
lib/ARSObject.pod view on Meta::CPAN
=> 0 || number of rows
(C<ARS methods>)
Max number of rows to retrieve from ARS server with C<query> method.
=item -meta
=> {...}
(C<Metadata>)
Forms metadata from ARS server:
{formName}->{-fields}->{fieldName}=>{},
{formName}->{-fldids}->{fieldId}=>{}.
Futher data model is directly given from ARS::ars_GetFieldTable()/ARS::ars_GetField()
excluding C<-metax>.
Additional parameters may be:
'fieldLbl' => label, 'fieldLblc' => label cmt
=item -metaid
=> {fieldId => {fieldName=>'name',FieldId=>id, strIn|strOut=>sub{}},...}
=item -metadn
=> {fieldName => {fieldName=>'name',FieldId=>id, strIn|strOut=>sub{}},...}
(C<Metadata>)
Commonly used fields with common names and value translation.
Data translation sub{}s may be specified as
'strOut'|'strIn' => sub(self,form,{field},$_=value){} -> translated value.
This sub{}s may use C<strOut>() and C<strIn> methods.
=item -metax
=> ['displayInstanceList','permissions']
(C<Metadata>)
Field parameters to exclude from C<-meta> to decrease memory usage.
=item -meta-min
(C<Metadata>)
Used by C<arsmetamin> internally.
=item -meta-sql
=> undef || {SQL Data Store metadata}
(C<Metadata>, C<SQL Data Store Methods>, C<Variable files>)
SQL Data Store metadata loaded or refreshed by C<arsmetasql>()/C<sqlname>():
{tableName}->{-cols}->{sqlName}=>{fieldName, sqlName,...}
{tableName}->{-fields}->{fieldName}=>sqlName
{tableName}->{-ids}->{fieldId}=>sqlName
{-forms}->{formName}->{tableName}
lib/ARSObject.pod view on Meta::CPAN
(C<CGI Form Presenter - Field Definitions>)
Condition to reset field value.
If C<-values> and field value unfound, it will be reset also.
=item -schema
=> undef || [form name, form name...]
(C<Metadata>)
ARS forms or schemas to use.
Metadata will be loaded to C<-meta> and may be cached with C<vfname>(C<-meta>)
if C<-schgen>.
=item -schfdo
=> 0 || 1
(C<Metadata>)
Include display only fields (AR_FIELD_OPTION_DISPLAY) into schema.
=item C<-schgen>
=> 1 || 0
|| 2 || 3 || [schema,...]
(C<Metadata>)
Cache metadata from ARS server using C<vfname>(C<-meta>)?
Or each session get metadata from ARS server.
0 - get metadata from server, do not use cache file.
1 - generate cache file if not exists, else load this file.
2 - renew schema definitions using timestamps.
3 - renew schema always.
[schema,...] - list of schemas to renew.
=item -smtp
=> undef || Net::SMTP object
lib/ARSObject.pod view on Meta::CPAN
=item -storable
=item -meta-storable
=item <-vfname>-storable
=> 1 || 0
(C<Variable files>)
Use L<Storable|Storable> module for variable files, metadata file, or another particular file?
Or L<Data::Dumper|Data/Dumper> will be used.
See also C<vstore>().
=item -srv
=> undef || 'ARS server name'
(C<Connection>)
ARS server name to connect
=item -strFields
=> 1 || 0 || 2
(C<ARS methods>)
Translate ARS field values using metadata and conversion sub{}s.
1 - using 'enumLimits' and C<strtime>/C<timestr>('yyyy-mm-dd hh:mm:ss'),
2 - using at first localisation metadata for enum fields ('fieldLbvl').
=item -undef
=> not exists || value
(C<CGI Form Presenter - Field Definitions>)
Field value to be treated as undef or null for database.
See also C<-value>.
=item -used
=> not exists == 1 || boolean || 'field name' || ['field name',..]
|| sub{}({self}, {field})
=item -unused
lib/ARSObject.pod view on Meta::CPAN
=item ars_errstr () -> $ARS::ars_errstr
(C<Error Processing and Echo>)
Last ARS error.
=item arsmeta (-param => value,...)
(C<Metadata>)
Load/refresh ARS metadata (C<vfload>/C<vfstore>(C<-meta>), C<-metadn>, C<-metaid>).
Called from C<connect>.
May be called without C<connect> if metadata file exists.
See also C<arsmetamin>.
=item arsmetamin (-param => value,...)
(C<Metadata>)
Refresh minimal ARS metadata set (C<vfstore>(C<-meta-min>)) after C<connect>/C<arsmeta> call.
Load minimal ARS metadata instead of or after C<connect>/C<arsmeta> call.
Loading of minimal metadata set is faster then loading all metadata with C<arsmeta>.
Minimal metadata set includes explicit 'enumLimits' and 'time' fields.
Synopsis: Refreshing C<-meta-min>:
$s->set(-schgen =>3);
$s->connect();
$s->arsmetamin();
=item arsmetasql (-param => value,...)
(C<Metadata>, C<SQL Data Store Methods>)
Load SQL Data Store metadata or refresh this from ARS metadata after C<connect>/C<arsmeta> call.
The SQL Data Store is intended for data replicated from ARS using C<dbidsrpl>() calls.
Database table and column names are escaped ARS form and field names.
Metadata is stored in C<-meta-sql> variable file.
Synopsis: Refreshing C<-meta-sql>:
$s->set(-schgen =>3);
$s->connect();
$s->dbi();
$s->arsmetasql();
$s->dbidsmetasync();
See also C<sqlname>(), C<dbidsmetasync>(), C<dbidsrpl>(), C<dbidsquery>()
lib/ARSObject.pod view on Meta::CPAN
Generate HTML textarea field using L<CGI|CGI>->textarea(@_)
=item connect (-param => value,...) -> connected
(C<Connection>)
Connect to ARS server with ARS::ars_Login()
or verify existed connection with ARS::ars_VerifyUser().
Load metadata (C<vfload>/C<vfstore>(C<-meta>), C<-metadn>, C<-metaid>).
=item cpcon (string,...) -> translated string,...
(C<Error Processing and Echo>)
Translate strings to console codepage using C<-cptran>.
lib/ARSObject.pod view on Meta::CPAN
=item dbi() -> DBI object
(C<Utility Objects>)
Access to L<DBI|DBI> object. C<dbiconnect> will be used if empty C<-dbi>.
=item dbiconnect (?-dbiconnect=> connection string || [DBI->connect args]) -> DBI object
(C<Utility Objects>)
Connect to L<DBI|DBI> database using C<-dbiconnect>.
=item dbido (dbi do args, , ?-echo=>1) -> dbi do result
(C<Utility Objects>)
Execute L<DBI|DBI> 'do' using C<dbi>.
Use -echo=>1 to output command to STDOUT.
=item dbidsmetasync (-echo => 0 || 1)
(C<Metadata>, C<SQL Data Store Methods>)
Sync SQL Data Store schema with metadata generated by C<arsmetasql>().
Uses C<dbi>(), C<-meta-sql>, C<-sqlschema>.
Calls C<dbido>('CREATE TABLE...') and C<dbido>('ALTER TABLE...').
=item dbidsrpl (-param => value)
(C<SQL Data Store Methods>)
Replicate ARS data to the SQL Data Store.
Uses C<dbi>(), C<-meta-sql>, C<-sqlschema>.
Parameters:
-echo => undef || 0 || 1
-form => ARS form name
-fields => undef || '*' || fields to replicate, alike C<query>(-fields)
-query => undef || ARS query string
lib/ARSObject.pod view on Meta::CPAN
-unused => undef || SQL where clause part to delete unused records from Data Store table. "ARS field name"s and "ARS form name"s may be used.
-sleep => undef || seconds to L<perlfunc::sleep|perlfunc> between calls to ARS.
=item dbidsquery (-param => value) -> ({fieldName => fieldValue,...},...)
(C<SQL Data Store Methods>)
Query data from SQL Data Store.
Uses C<dbi>(), C<-meta-sql>, C<-sqlschema>.
Any C<dbi>() method may be used for SQL Data Store,
but C<dbidsquery> understands "ARS form name"s and "ARS field name"s
in addition to "sql table name"s and "sql column name"s.
Records are returned as hash refs with ARS field names available,
otherwise SQL column names.
Parameters:
-echo => undef || 0 || 1
lib/ARSObject.pod view on Meta::CPAN
=item dbierrstr () -> dbi->errstr
(C<Error Processing and Echo>)
Last L<DBI|DBI> error, <dbi>->errstr
=item dbiquery (dbi query args, ?-echo=>1) -> dbi cursor object
(C<Utility Objects>)
Query L<DBI|DBI> database using C<dbi>, 'prepare', 'execute'.
Use -echo=>1 to output command to STDOUT.
=item dscmp (data1, data2) -> cmp
(C<Utility Methods>)
Compare two data structures alike L<cmp|perlop>.
=item dsdump (data structure) -> dump string
(C<Utility Methods>)
Stringify any data structure using L<Data::Dumper|Data/Dumper>.
This string may be loaded back with C<dsparse>().
=item dsmerge (array ref,...) -> [merged array]
=item dsmerge (hash ref,...) -> {merged hash}
(C<Utility Methods>)
Sequentally assign elements of data structures given to result data structure.
=item dsparse (perl string) -> data structure
(C<Utility Methods>)
Convert C<dsdump>ed string to data structure.
=item dsquot (data structure) -> stringified
=item dsquot1 (data structure) -> stringified, defined elements only
(C<Utility Methods>)
Quote (stringify) any data structure to human readable form.
=item dsunique (item,...) -> (unique items)
(C<Utility Methods>)
Find unique items in the list given.
lib/ARSObject.pod view on Meta::CPAN
-id => entryId
-fields => [internalId | fieldName,...]
-for => {} # steady hash to store each entry fetched
-echo=>1 # output command to STDOUT
=item entryBLOB (-form=>form, -id=>entryId, -field=>fieldId|fieldName) -> data
=item entryBLOB (..., -set=>data) -> id
=item entryBLOB (..., -file=>path, ?-set=>1) -> id
(C<ARS methods>)
Retrieve BLOB field using ARS::ars_GetEntryBLOB()
or update BLOB field using C<entryUpd>().
Parameters:
-form | -schema | -from | -into => schema or form name
-id=>entryId
-echo=>1 # output command to STDOUT
-field=>fieldId | fieldName
-file=>path, -set=>boolean # when using file for BLOB field data
-set=>data # when updating BLOB field from scalar data
=item entryDel (-form=>form, -id=>entryId, ?-echo=>1) -> id
(C<ARS methods>)
Delete record into ARS using ARS::ars_DeleteEntry().
Parameters:
-form | -into | -schema => schema or form name
lib/ARSObject.pod view on Meta::CPAN
=item fdirls (..., []) -> [entry,...]
(C<Utility Methods>)
List directory contents.
=item fload (?-opt, filename) -> content
(C<Utility Methods>)
Load data from file.
Options: '-b' - L<binmode|perlfunc>.
See also C<fstore>.
=item fopen (?-opt, filename) -> IO::File object
(C<Utility Methods>)
Open file with L<IO::File|IO/File> object.
Options: '-b' - L<binmode|perlfunc>.
See also C<fload>, C<fstore>.
=item fstore (?-opt, filename, string,...) -> success
(C<Utility Methods>)
Store strings to file.
Options: '-b' - L<binmode|perlfunc>.
Filename may be started with '>>' to add data to file.
See also C<fload>.
=item lsflds (additional field properties) -> list of field descriptions
(C<Metadata>)
List field descriptions from C<-meta>.
May be useful when scripting.
Or set C<-storable> => 0 and view C<vfname>(C<-meta>) file.
=item new (param => value,...) -> ARSObject
(C<Creation and Configuration>)
Create ARSObject.
lib/ARSObject.pod view on Meta::CPAN
-limit ||-max => maxRetrieve # ARS::ars_GetListEntry() parameter
-for ||-foreach => sub(self, form, id|string, ?{record}){die "last\n", die "next\n"} -> self
# iterator sub{} for each row
-echo => 1
# output query and details to STDOUT
=item schema () -> {schemaName => {metadata},...}
=item schema (schema name) -> {schema metadata} || undef
=item schfld (schema) -> {fieldName=>{field metadata},...}
=item schfld (schema, field name | meta) -> {field metadata} || undef
=item schid (schema, field '-metaid' | id) -> {fieldName=>'name', FieldId=>id}
=item schdn (schema, field '-metadn' | name) -> {fieldName=>'name', FieldId=>id}
=item schvals (schema, field name | id | meta) -> [itemNumber,...] || undef
=item schlbls (schema, field name | id | meta) -> {itemNumber => itemName,...} || undef
=item schlblsl (schema, field name | id | meta) -> {itemNumber => localised itemName,...} || undef
(C<Metadata>)
Access to ARS metadata loaded by C<connect>, C<arsmeta>, C<arsmetamin>.
=item set (param => value,...) -> self
=item set (param) -> value
(C<Creation and Configuration>)
Configure ARSObject.
lib/ARSObject.pod view on Meta::CPAN
=item smtpconnect (?-smtphost=> name) -> Net::SMTP object
(C<Utility Objects>)
Connect to L<Net::SMTP|Net/SMTP> host using C<-smtphost>.
=item smtpsend (-from || -sender => name, -to || -recipient => [name,...], -data => smtp data || (-subject => string, -text || -html => text)) -> Net::SMTP::dataend
(C<Utility Objects>)
Send L<Net::SMTP|Net/SMTP> e-mail using C<smtp>.
=item soon (minutes number || sub{}, logfile ||'', run command || [command line] || sub{}, soon command || [command line] || [])
=item soon (minutes number || sub{}, logfile ||'', run command || [command line] || sub{})
lib/ARSObject.pod view on Meta::CPAN
Execute the script periodically, run command immediately, soon command after delay specified.
Log file name may be full file name, else C<vfname>(file name) will be used.
If run command is empty, soon command will be scheduled.
If soon command is empty, sleep(minutes*60) will be used, otherwise 'at' MSWin32 scheduling command.
If !defined(minutes), soon command will be deleted from schedule and run command will be executed once.
=item sqlname (formName, ?fieldName, ?forceMetaUpd) -> sql name
(C<Metadata>, C<SQL Data Store Methods>)
Get SQL Data Store table or column name converted from ARS form and field name.
Used by C<arsmetasql>().
Uses C<-sqlname>, C<-sqlntbl>, C<-sqlncol>, C<-sqlninc> settings.
=item strIn (schema, fieldId | fieldName | field metadata, value) -> converted
(C<ARS methods>)
Convert value for ARS internal field value representation.
Called automatically when C<-strFields>.
Should be called explicitly from C<strIn> sub{} in C<-metadn>/C<-metaid>.
May need to be called explicitly forming C<query> condition.
See also C<strOut>, C<-strFields>.
=item strOut (schema, fieldId | fieldName | field metadata, fieldValue) -> converted
(C<ARS methods>)
Convert ARS field value for external representation.
Called automatically when C<-strFields>.
Should be called explicitly from C<strOut> sub{} in C<-metadn>/C<-metaid>
and when parsing strings result from C<query>.
See also C<strIn>, C<-strFields>.
lib/ARSObject.pod view on Meta::CPAN
(C<Utility Methods>)
Convert stringified with C<strtime> time string to seconds form
with L<POSIX::mktime|POSIX>
=item vfclear (-slotName) -> true
(C<Variable files>)
Clear data loaded from variables file by C<vfload>(-slotName).
Reset data buffers of C<vfdata>() and C<vfhash>().
=item vfdata (-slotName) -> data structure
=item vfdata (-slotName, index) -> numbered element of data array
=item vfdata (-slotName, filter sub{}(self, -slot, index, $_=elem)) -> [record,...]
(C<Variable files>)
Access to data of variables file.
Automatically C<fload>s it.
Data structure will be treated as an array ref when index or filter argument used.
=item vfdistinct (-slotName, keyName) -> [value,...]
=item vfdistinct (-slotName, keyName, filter sub{}(self, -slot, keyName, keyValue, $_=elem)) -> [value,...]
(C<Variable files>)
Distinct values from C<vfdata>,
alike [sort keys %{C<vfhash>(-slotName, keyName)}].
Each element of C<vfdata>(-slotName) should be a hash with 'keyName' element.
=item vfhash (-slotName, keyName) -> {keyName=>{key => value},...}
=item vfhash (-slotName, keyName, keyValue) -> {key => value}
=item vfhash (-slotName, keyName, keyValue, key) -> value || undef if !ref(keyValue)
=item vfhash (-slotName, keyName, filter sub{}(self, -slot, keyName, keyValue, $_=elem)) -> {keyName=>{key => value},...}
(C<Variable files>)
Direct access to C<vfdata> using key name and value.
Each element of C<vfdata>(-slotName) array should be a hash with 'keyName' element.
C<vfdata> array will be automatically cached into hash "-slotName/keyName".
=item vfload (partial file name || -slotName) -> data structure
=item vfload (-slotName, ?create, ?renew ||renew period seconds) -> data structure
(C<Variable files>)
Load data structure from variables file using C<fload> and C<-storable>/C<dsparse>.
File absent may be created.
File existed may be renewed immediatelly or if it is older then renew period.
If '-slotName' specified, this slot will contain loaded data structure.
If '-slotName-calc' => sub{}(self, -slotName) specified, file will not be used at all,
data will be calculated on demand.
If '-slotName-load' => sub{}(self, -slotName) specified, it will be used to fill unexisted file.
=item vfname (partial name || -slotName) -> full var file path name in the filesystem
(C<Variable files>)
Convert partial file name to full, based on C<-vfbase>, for variables file.
Leading '-' will be excluded.
lib/ARSObject.pod view on Meta::CPAN
=item vfrenew (-slotName, ?renew period seconds) -> vfstore()/vfload()
(C<Variable files>)
Renew variables file using C<vfstore>() inside C<vfload>() with '-slotName-load' sub{}.
If no period or when period ==1 file will be renewed immediatelly.
Else file will be renewed only if it is older then period.
=item vfstore (partial file name, data structure) -> success
=item vfstore (-slotName) -> success
(C<Variable files>)
Store data to variables file using C<-storable>/C<dsdump> and C<fstore>.
If '-slotName' specified, this slot should contain data structure to be stored.
If '-slotName-storable' => switch specified, it will be used instead of C<-storable>.
=back
=head1 VERSION
lib/ARSObject.pod view on Meta::CPAN
Publishing 0.57 version
=head2 2012-05-16
Publishing 0.56 version
=head2 2012-04-24
Added field localisation metadata, see source code for 'fieldLbll' and 'fieldLbvl'.
Updated C<lsflds>().
Added C<schlblsl>().
Added C<-strFields> => 2 - translate ARS enum field values using at first
localisation metadata ('fieldLbvl').
Extended C<arsmetamin>() data with 'time' fields.
Added C<-metadb> to C<CGI Form Presenter - Field Definitions>.
=head2 2012-03-23
New C<SQL Data Store Methods>
NAME
ARSObject - high level interface above ARS module
DESCRIPTION
This module is intended for capable scripts above ARS module.
It caches metadata alike Remedy::ARSTools, but uses Data::Dumper or Storable module. And metadata model is directly given from ARS::ars_GetFieldTable()/ARS::ars_GetField(), unlike ARSOOForm and Remedy::ARSTools. And additional description level (-met...
Field names and values are translated as possible.
query() method supports iterator sub{} and uses ARS::ars_GetListEntry(), ARS::ars_GetListEntryWithFields(), ARS::ars_GetEntry() calls as appropriate with parameters given.
entry(), entryIns(), entryUpd(), entryDel() methods are usual to manipulate records.
entryNew() method may be used to form new record hash with default values for entryIns().
entryDif() method may be used to minimise data for entryUpd().
AUTOLOAD() method is to call 'ARS::ars_XXX' functions as methods.
Special processing added for 'HPD:Help Desk' ITSM Suite form.
Variable files may be used to cache any data.
Misc Utility Methods intended for strings, dates, data structures.
Utility Objects added to simplify and unify access to DBI, CGI, Net::SMTP modules.
LICENSE
This is free software; you can use redistribute it and/or modify it
under the same terms as Perl itself.