File Coverage

blib/lib/Data/Generate.pm
Criterion Covered Total %
statement 546 569 95.9
branch 121 148 81.7
condition 53 69 76.8
subroutine 55 56 98.2
pod 38 38 100.0
total 813 880 92.3


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -w
2             ################################################################################
3             # package Data::Generate
4             # Description: returns an SQL-Data generator object
5             # Design: during parsing we create following data structure internally:
6             # 'value_term': ascii string
7             # 'value_column': array of possible alternative choices for the value term
8             # 'value_chain': a chain of value columns
9             # 'chain_list': the generator itself
10             # output data : output data is retrieved by subsequent concatenation
11             # of value terms in a value chain. If more than one value chains are defined,
12             # then, based on weigthing, each chain at turn will be "asked" to return an
13             # output value, until an array of the requested cardinality is filled.
14             #
15             ################################################################################
16             package Data::Generate;
17            
18              
19 4     4   243933 use 5.006;
  4         52  
20 4     4   22 use strict;
  4         4  
  4         66  
21 4     4   17 use warnings;
  4         8  
  4         77  
22 4     4   17 use Carp;
  4         4  
  4         180  
23 4     4   4152 use Parse::RecDescent;
  4         145776  
  4         26  
24 4     4   1777 use Date::Parse;
  4         26386  
  4         506  
25 4     4   1540 use Date::DayOfWeek;
  4         5489  
  4         193  
26              
27 4     4   29 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
  4         7  
  4         1067  
28             require Exporter;
29              
30              
31             our @ISA = qw(Exporter);
32              
33              
34              
35              
36             # Items to export into callers namespace by default. Note: do not export
37             # names by default without a very good reason. Use EXPORT_OK instead.
38             # Do not simply export all your public functions/methods/constants.
39              
40             # This allows declaration use Data::Generate ':all';
41             our %EXPORT_TAGS = ( 'all' => [ qw(
42             parse
43             ) ] );
44             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
45             our @EXPORT = qw();
46             our $VERSION = '1.24';
47              
48              
49             $Data::Generate::Parser=undef;
50             $Data::Generate::current=undef;
51             $Data::Generate::ACTUAL_VALUE_COLUMN=undef;
52             $Data::Generate::VC_RANGE_REVERSE_FLAG=undef;
53              
54              
55              
56             #-------------------------------------------------------------------------------
57             # Various constant definitions
58             #-------------------------------------------------------------------------------
59             $Data::Generate::vcol_type ={};
60             $Data::Generate::vcol_type->{year}->{lowlimit}=1970; # Unix 32 bit date
61             $Data::Generate::vcol_type->{year}->{highlimit}=2037; # Unix 32 bit date
62             $Data::Generate::vcol_type->{year}->{type}='year';
63             $Data::Generate::vcol_type->{month}->{lowlimit}=1;
64             $Data::Generate::vcol_type->{month}->{highlimit}=12;
65             $Data::Generate::vcol_type->{month}->{type}='month';
66             $Data::Generate::vcol_type->{day}->{lowlimit}=1;
67             $Data::Generate::vcol_type->{day}->{highlimit}=31;
68             $Data::Generate::vcol_type->{day}->{type}='day';
69             $Data::Generate::vcol_type->{hour}->{lowlimit}=0;
70             $Data::Generate::vcol_type->{hour}->{highlimit}=24;
71             $Data::Generate::vcol_type->{hour}->{type}='hour';
72             $Data::Generate::vcol_type->{minute}->{lowlimit}=0;
73             $Data::Generate::vcol_type->{minute}->{highlimit}=59;
74             $Data::Generate::vcol_type->{minute}->{type}='minute';
75             $Data::Generate::vcol_type->{second}->{lowlimit}=0;
76             $Data::Generate::vcol_type->{second}->{highlimit}=59;
77             $Data::Generate::vcol_type->{second}->{type}='second';
78             $Data::Generate::vcol_type->{fraction}->{type}='fraction';
79              
80             $Data::Generate::vchain_type ={};
81             $Data::Generate::vchain_type->{DATE}->{type}='DATE';
82             $Data::Generate::vchain_type->{DATE}->{vcol_output_format}=
83             ['%s',' %02d:','%02d:','%02d','.%s'];
84             # ['%04d','%02d','%02d',' %02d:','%02d:','%02d','.%s'];
85             $Data::Generate::vchain_type->{DATE}->{check_type}=sub {
86 4     4   26 no warnings "all";
  4         7  
  4         1072  
87             my $input=shift;
88             (my $ss,my $mm, my $hh,my $day,my $month,my $year)= strptime($input);
89             return undef unless defined $year;
90             $year+=1900;
91             $month++;
92             my $precision=0;
93             $precision = $Data::Generate::current->{ct_precision}
94             if defined $Data::Generate::current->{ct_precision};
95             my $result=sprintf('%04d%02d%02d %02d:%02d:%02.'.$precision.'f',
96             $year, $month, $day,$hh,$mm,$ss);
97             return undef unless defined str2time($result);
98             return $result;
99             };
100             $Data::Generate::vchain_type->{DATE}->{output_format_fct}=sub {
101             my $input=shift;
102             return $input unless defined $Data::Generate::current->{ct_precision};
103             my $precision=$Data::Generate::current->{ct_precision};
104             my ( $date_string, $date_fraction) = ($input =~ /^(.+?)(\d{2}\.\d*)$/);
105             $date_fraction=sprintf('%02.'.$precision.'f',$date_fraction);
106             return $date_string.$date_fraction;
107             };
108              
109             $Data::Generate::vchain_type->{DATE}->{subtype}->{'DATEWITHFRACTION'}
110             ->{fraction_start_ix}=4;
111              
112              
113             $Data::Generate::vchain_type->{INTEGER}->{type}='INTEGER';
114             $Data::Generate::vchain_type->{INTEGER}->{check_type}=sub {
115 4     4   32 no warnings "all";
  4         12  
  4         22441  
116             my $input=shift;
117             my $result=int($input);
118             return undef unless $result == $input;
119             return $result;
120             };
121              
122             $Data::Generate::vchain_type->{FLOAT}->{output_format_fct}=sub {
123             my $input=shift;
124             $input =~ s/^\-0+\.0+$/0.0/;
125             $input =~ s/^\+//;
126             return eval($input);
127             };
128              
129             $Data::Generate::vchain_type->{FLOAT}->{check_type}=sub {
130             # no warnings "all";
131             my $input=shift;
132             my $result=$input*1.0;
133             $input=eval($input);
134             $result=eval($result);
135             return undef unless $result == $input;
136             return $result;
137             };
138              
139              
140             $Data::Generate::vcol_type->{weekday}->{type}='weekday';
141             $Data::Generate::vcol_type->{weekday}->{term_list}=[qw{SUN MON TUE WED THU FRI SAT}];
142              
143             ################################################################################
144             # sub new
145             # Description:
146             # inital constructor for a list of value chains.
147             #
148             ################################################################################
149             sub new
150             {
151 29     29 1 56 my ($class,$text) = @_;
152 29         54 my $self = {};
153 29         64 $self->{vchain_text} = $text;
154 29         48 $self->{vchain_length} = 0;
155 29         80 $self->{data_array} = [''];
156 29         50 $self->{vchain_array} = [];
157 29         57 $self->{vchain_hash} = {};
158 29         41 $self->{actual_vcol} = {};
159 29         52 bless $self, $class;
160 29         216 $self->reset_actual_vchain();
161 29         395 return $self;
162             }
163            
164              
165              
166             ################################################################################
167             # sub load_parser
168             # Description:
169             # create a Parse::RecDescent parser
170             # and load Data::Generate grammatics into.
171             #
172             ################################################################################
173             sub load_parser
174             {
175              
176             #------------------------------------------------------------------------------#
177             # START OF GRAMMATICS #
178             #------------------------------------------------------------------------------#
179              
180 4     4 1 9 my $grammar = q {
181             start: varchar_type
182             | string_type
183             | date_type
184             | integer_type
185             | float_type
186            
187             #------------------------------------------------------------------------------#
188             # STRING TYPE GRAMMATICS #
189             #------------------------------------------------------------------------------#
190             # different intialization, but for the rest see varchar type
191              
192             string_type: ct_string vch_list
193              
194             ct_string: /STRING/
195             {
196             $Data::Generate::current->{chain_type}='STRING';
197             }
198             #------------------------------------------------------------------------------#
199             # VARCHAR TYPE GRAMMATICS #
200             #------------------------------------------------------------------------------#
201              
202             varchar_type: ct_varchar vch_list
203              
204             ct_varchar: /(VC2|VC|VARCHAR2|VARCHAR)/ '(' /\d+/ ')'
205             {
206             $Data::Generate::current->{chain_type}='VARCHAR';
207             $Data::Generate::current->{ct_length}=$item[3];
208             }
209              
210             vch_list:
211              
212             value_chain: value_col(s) vchain_weigth(?)
213             {
214             $Data::Generate::current->bind_actual_vchain();
215             1; }
216            
217             vchain_weigth: /\(/ /\d+\.?\d*/ /\%\)/
218             { $Data::Generate::current->{actual_vchain}->{weigth}=$item[2]; 1; }
219              
220             value_col: vcr_integer vcol_card(?)
221             {
222             $Data::Generate::current->bind_actual_vcol();
223             1;
224             }
225             | vcol_range
226             | vcol_literal
227             | vcol_filelist
228              
229              
230              
231             vcol_literal: vcol_lit_term vcol_card(?)
232             {
233             $Data::Generate::current->bind_actual_vcol();
234             1;
235             }
236              
237              
238             vcol_card: '{' /\d+/ '}'
239             {
240             $Data::Generate::current->{actual_vcol}->{quantifier}=$item[2];
241             1;
242             }
243              
244             vcol_lit_term: /\'.+?\'/
245             {
246             $item[1] =~ /\'(.+?)\'/;
247             push(@{$Data::Generate::current->
248             {actual_vcol}->{value_term_list}},$1); 1;
249             }
250              
251             vcol_range: vcr_start vcr_reverse(?) vcr_term(s) vcr_end vcol_card(?)
252             {
253             $Data::Generate::current->check_reverse_flag();
254             $Data::Generate::current->bind_actual_vcol();
255             1;}
256              
257              
258             vcr_start: /\[/
259              
260             vcr_reverse: /\^/ { $Data::Generate::current->{actual_vcol}
261             ->{reverse_flag}=1; }
262              
263              
264             vcr_term: /[^\s\]\[]/ '-' /[^\s\]\[]/
265             {
266             my @cmp = map(chr,
267             (
268             ord($item[1])..ord($item[3])
269             )
270             );
271             push(@{$Data::Generate::current->
272             {actual_vcol}->{value_term_list}},@cmp);
273             }
274             | '\\\\ '
275             {
276             push(@{$Data::Generate::current->
277             {actual_vcol}->{value_term_list}},' ');
278             }
279             | '\\\\' /./
280             {
281             push(@{$Data::Generate::current->
282             {actual_vcol}->{value_term_list}},$item[2]);
283             }
284             | /[^\]\[]/
285             {
286             push(@{$Data::Generate::current->
287             {actual_vcol}->{value_term_list}},$item[1]);
288             }
289              
290             vcr_end: /\]/
291              
292              
293             vcr_integer: /\[/ /\d+/ '..' /\d+/ /\]/
294             {
295             warn "false integer order " if $item[4] < $item[2];
296             my @cmp = ($item[2]..$item[4]);
297             push(@{$Data::Generate::current->
298             {actual_vcol}->{value_term_list}},@cmp);
299             }
300              
301              
302             vcol_filelist: vcol_filelist_term vcol_card(?)
303             {
304             $Data::Generate::current->bind_actual_vcol();
305             1;
306             }
307              
308              
309             vcol_filelist_term: /\<\S+\>/
310             {
311             (my $file)= ($item[1] =~ /\<(\S+)\>/);
312             $Data::Generate::current->vcol_file_process($file);
313             1;
314             }
315              
316              
317              
318            
319             #------------------------------------------------------------------------------#
320             # INTEGER TYPE GRAMMATICS #
321             #------------------------------------------------------------------------------#
322              
323             integer_type: ct_integer vch_int_list
324              
325             ct_integer: /(INTEGER|INT)/ ct_int_length(?)
326             {
327             $Data::Generate::current->{chain_type}='INTEGER';
328             $Data::Generate::current->{ct_length}=9 # max integer value
329             unless (exists $Data::Generate::current->{ct_length});
330            
331             if ($Data::Generate::current->{ct_length}>9)
332             {
333             warn " maximal integer length is 9 \n".
334             "Current Value: $Data::Generate::current->{ct_length} is too high"
335             .",will use length 9.";
336             $Data::Generate::current->{ct_length}=9;
337             }
338             }
339              
340             ct_int_length: '(' /\d+/ ')'
341             {
342             $Data::Generate::current->{ct_length}=$item[2];
343             }
344              
345             vch_int_list:
346              
347              
348             vch_int: vchi_sign(?) vcol_int(s) vchain_weigth(?)
349             {
350             $Data::Generate::current->bind_actual_vchain();
351             1; }
352              
353             vchi_sign:
354             /\+\/\-/
355             {
356             $Data::Generate::current->{actual_vchain}->{sign}->{'+'}++;
357             $Data::Generate::current->{actual_vchain}->{sign}->{'-'}++;
358             1; }
359             | /[+-]/
360             {
361             $Data::Generate::current->{actual_vchain}->{sign}->{$item[1]}++;
362             1; }
363            
364              
365              
366             vcol_int: vcint_range
367             | vcint_literal
368             | vcol_filelist
369              
370             vcint_range: /\[/ /\]/ vcint_card(?)
371             {
372             $Data::Generate::current->bind_actual_vcol();
373             1;}
374              
375              
376             vcint_term: /\d+/ '-' /\d+/
377             {
378             my @cmp = (($item[1]+0)..($item[3]+0));
379             push(@{$Data::Generate::current->
380             {actual_vcol}->{value_term_list}},@cmp);
381             }
382             | vcint_lit_term
383              
384             vcint_literal: vcint_lit_term vcint_card(?)
385             {
386             $Data::Generate::current->bind_actual_vcol();
387             1;
388             }
389              
390             vcint_lit_term: /\d+/
391             {
392             push(@{$Data::Generate::current->
393             {actual_vcol}->{value_term_list}},($item[1]+0));
394             }
395              
396             vcint_card: '{' /\d+/ '}'
397             {
398             $Data::Generate::current->{actual_vcol}->{quantifier}=$item[2];
399             1;
400             }
401              
402             #------------------------------------------------------------------------------#
403             # FLOAT TYPE GRAMMATICS #
404             #------------------------------------------------------------------------------#
405              
406             float_type: ct_float vch_float_list
407              
408             ct_float: /FLOAT/ '(' /\d+/ ')'
409             {
410             $Data::Generate::current->{chain_type}='FLOAT';
411             $Data::Generate::current->{ct_length}=$item[3];
412             }
413            
414             vch_float_list:
415            
416              
417              
418             vch_float: vchfloat_filelist
419             | vcol_float_int_part vcol_float_fraction vcol_float_exponent(?) vchain_weigth(?)
420             {
421             $Data::Generate::current->{actual_vchain}
422             ->{chain_subtype}='FLOATTOTAL';
423             $Data::Generate::current->bind_actual_vchain();
424             1; }
425            
426              
427             vchfloat_filelist: /\<\S+\>/
428             {
429             $Data::Generate::current->{actual_vchain}
430             ->{chain_subtype}='FLOATLIST';
431             (my $file)= ($item[1] =~ /\<(\S+)\>/);
432             $Data::Generate::current->vcol_file_process($file);
433             $Data::Generate::current->bind_actual_vcol();
434             $Data::Generate::current->bind_actual_vchain();
435             1;
436             }
437              
438              
439              
440             vcol_float_int_part: vchi_sign(?) vcol_int(s)
441             {
442             $Data::Generate::current->{actual_vchain}
443             ->{chain_subtype}='FLOATINTPART';
444             $Data::Generate::current->bind_actual_vchain();
445             1; }
446              
447              
448             vcol_float_exponent: 'E' vcfloat_exp_sign(?) vcfloat_exp_term
449             {
450             $Data::Generate::current->{actual_vchain}
451             ->{chain_subtype}='FLOATEXP';
452             $Data::Generate::current->bind_actual_vchain();
453             1; }
454              
455              
456             vcfloat_exp_sign: /[+-]/
457             {
458             $Data::Generate::current->{actual_vchain}->{sign}->{$item[1]}++;
459             1; }
460              
461              
462             vcfloat_exp_term: vcfloatexp_lit_term
463             {
464             $Data::Generate::current->bind_actual_vcol();
465             1;
466             }
467              
468             vcfloatexp_lit_term: /\d+/
469             {
470             push(@{$Data::Generate::current->
471             {actual_vcol}->{value_term_list}},($item[1]+0));
472             1;
473             }
474              
475             vcol_float_fraction: '.' vcol_fraction
476             {
477             $Data::Generate::current->{actual_vchain}
478             ->{chain_subtype}='FLOATFRACTION';
479             $Data::Generate::current->bind_actual_vchain();
480             1;
481             }
482              
483              
484             #------------------------------------------------------------------------------#
485             # DATE TYPE GRAMMATICS #
486             #------------------------------------------------------------------------------#
487              
488             date_type: ct_date ct_date_precision(?) vch_date_list
489              
490             ct_date: /(DT|DATE)/
491             {
492             $Data::Generate::current->{chain_type}='DATE';
493             $Data::Generate::current->{ct_length}=17;
494             }
495              
496             ct_date_precision: '(' /\d+/ ')'
497             {
498             $Data::Generate::current->{ct_precision}=$item[2];
499             if ($Data::Generate::current->{ct_precision}>14)
500             {
501             warn " maximal precision for fraction of seconds is 14 \n".
502             "Current Value: $Data::Generate::current->{ct_precision} is too high"
503             .",will use precision 14.";
504             $Data::Generate::current->{ct_precision}=14;
505             }
506              
507             $Data::Generate::current->{ct_length}+=
508             $Data::Generate::current->{ct_precision}+1; # +1 because of dot sign
509             }
510              
511              
512              
513             vch_date_list:
514              
515             vch_date: vcol_year vcol_month vcol_day vcol_time(?) vchain_weigth(?)
516             {
517             $Data::Generate::current->bind_actual_vchain();
518             1; }
519             | vchdate_filelist
520              
521              
522             vchdate_filelist: /\<\S+\>/
523             {
524             (my $file)= ($item[1] =~ /\<(\S+)\>/);
525             $Data::Generate::current->vcol_file_process($file);
526             $Data::Generate::current->bind_actual_vcol();
527             $Data::Generate::current->bind_actual_vchain();
528             1;
529             }
530              
531              
532             vcol_time: vcol_hour ':' vcol_min ':' vcol_sec vcol_date_fraction(?)
533              
534             vcol_year: vcdate_range
535             { $Data::Generate::current->bind_vcol_range('year'); 1;}
536             | vcdate_literal
537             { $Data::Generate::current->bind_vcol_literal('year'); 1;}
538              
539             vcol_month: vcmonth_range
540             { $Data::Generate::current->bind_vcol_range('month'); 1;}
541             | vcmonth_literal
542             {
543             my $litval=shift(@{$Data::Generate::current->{actual_vcol}->{month_literal_values}});
544             $Data::Generate::current->{actual_vcol}->{literal_value}=$litval;
545             $Data::Generate::current->bind_vcol_literal('month'); 1;}
546              
547             vcol_day: vcday_range
548             { $Data::Generate::current->bind_vcol_range('day'); 1;}
549             | vcdate_literal
550             { $Data::Generate::current->bind_vcol_literal('day'); 1;}
551              
552             vcol_hour: vcdate_range
553             { $Data::Generate::current->bind_vcol_range('hour'); 1;}
554             | vcdate_literal
555             { $Data::Generate::current->bind_vcol_literal('hour'); 1;}
556              
557             vcol_min: vcdate_range
558             { $Data::Generate::current->bind_vcol_range('minute'); 1;}
559             | vcdate_literal
560             { $Data::Generate::current->bind_vcol_literal('minute'); 1;}
561              
562             vcol_sec: vcdate_range
563             { $Data::Generate::current->bind_vcol_range('sec'); 1;}
564             | vcdate_literal
565             { $Data::Generate::current->bind_vcol_literal('sec'); 1;}
566              
567             vcol_date_fraction: '.' vcol_fraction
568             {
569             $Data::Generate::current->{actual_vchain}
570             ->{chain_subtype}='DATEWITHFRACTION';
571             1;
572             }
573              
574             vcdate_literal: /\d+/
575             {
576             $Data::Generate::current->{actual_vcol}->{literal_value}=$item[1];
577             1;
578             }
579              
580            
581             vcdate_range: /\[/ /\]/
582              
583             vcdate_term: /\d+/ '-' /\d+/
584             { $Data::Generate::current->add_term_range($item[1],$item[3]);1; }
585             | /\d+/
586             {
587             push(@{$Data::Generate::current->{actual_vcol}->{value_term_list}},
588             $item[1]); 1;
589             }
590              
591              
592             vcday_range: /\[/ /\]/
593            
594             vcday_term: vcdate_term
595             |
596             {
597             my $low =shift(@{$Data::Generate::current->{actual_vcol}->{weekday_index_values}});
598             my $high =shift(@{$Data::Generate::current->{actual_vcol}->{weekday_index_values}});
599             push(@{$Data::Generate::current->{actual_vcol}->{weekday_term_list}},
600             $low) unless defined $high;
601             $Data::Generate::current-> add_weekday_term_range($low,$high)
602             if defined $high;
603             1;
604             }
605              
606              
607             vcday_literal: /[a-zA-Z]+/
608             {
609             my @week=@{$Data::Generate::vcol_type->{weekday}->{term_list}};
610             my $ix=-1;
611             foreach my $wday_ix (0..$#week)
612             {
613             $ix=$wday_ix if $item[1] =~ /^$week[$wday_ix]/i;
614             }
615             die "cant process day term $item[1] " if $ix==-1;
616             push(@{$Data::Generate::current->{actual_vcol}->{weekday_index_values}}
617             ,$ix);
618             1;
619             }
620              
621             vcmonth_range: /\[/ /\]/
622              
623             vcmonth_term:
624             {
625             my $low =shift(@{$Data::Generate::current->{actual_vcol}->{month_literal_values}});
626             my $high =shift(@{$Data::Generate::current->{actual_vcol}->{month_literal_values}});
627             push(@{$Data::Generate::current->{actual_vcol}->{value_term_list}},
628             $low) unless defined $high;
629             $Data::Generate::current->add_term_range($low,$high)
630             if defined $high;
631             1;
632             }
633              
634             vcmonth_literal: /(\d+|[a-zA-Z]+)/
635             {
636             my $month=undef;
637             if ($item[1] =~ /\d+/)
638             {
639             $month =$item[1];
640             }
641             else
642             {
643             (undef,undef,undef,undef,$month,undef,undef) = Date::Parse::strptime($item[1].' 01');
644             die "Month $item[2] invalid " unless defined $month;
645             ++$month;
646             }
647             push(@{$Data::Generate::current->{actual_vcol}->{month_literal_values}}
648             ,$month);
649             1;
650             }
651              
652             #------------------------------------------------------------------------------#
653             # FRACTION SUBTYPE GRAMMATICS #
654             # (RELEVANT FOR DATE AND FLOAT) #
655             #------------------------------------------------------------------------------#
656              
657             vcol_fraction: vcol_fract(s)
658              
659             vcol_fract: vcfract_range
660             | vcfract_literal
661              
662             vcfract_range: /\[/ /\]/ vcfract_card(?)
663             {
664             $Data::Generate::current->bind_actual_vcol();
665             1;}
666              
667              
668             vcfract_term: /\d+/ '-' /\d+/
669             {
670             my @cmp = (($item[1]+0)..($item[3]+0));
671             push(@{$Data::Generate::current->
672             {actual_vcol}->{value_term_list}},@cmp);
673             }
674             | vcfract_lit_term
675              
676             vcfract_literal: vcfract_lit_term vcfract_card(?)
677             {
678             $Data::Generate::current->bind_actual_vcol();
679             1;
680             }
681              
682             vcfract_lit_term: /\d+/
683             {
684             push(@{$Data::Generate::current->
685             {actual_vcol}->{value_term_list}},($item[1]+0));
686             }
687              
688             vcfract_card: '{' /\d+/ '}'
689             {
690             $Data::Generate::current->{actual_vcol}->{quantifier}=$item[2];
691             1;
692             }
693             };
694             #------------------------------------------------------------------------------#
695             # END OF GRAMMATICS #
696             #------------------------------------------------------------------------------#
697              
698 4         29 my $parser = Parse::RecDescent->new($grammar);
699 4 50       1412586 defined $parser or carp "couldn't load parser";
700 4         14 return $parser;
701              
702             }
703              
704              
705             ################################################################################
706             # Description: helper function
707             ################################################################################
708             sub check_reverse_flag
709             {
710 12     12 1 34031 my $self =shift;
711 12 100       180 return unless exists $self->{actual_vcol}->{reverse_flag};
712             $self->{actual_vcol}->{value_term_list}=
713 1         4 $self->get_value_column_reverse($self->{actual_vcol}->{value_term_list});
714 1         20 delete $self->{actual_vcol}->{reverse_flag};
715             }
716              
717             ################################################################################
718             # Description: helper function
719             ################################################################################
720             sub check_range_order ($$)
721             {
722 16     16 1 24 my $min =shift;
723 16         19 my $max =shift;
724 16 50       49 if ($min >$max )
725             {
726 0         0 carp "false range order, $min > $max".
727             " will invert limits";
728 0         0 return [$max, $min];
729             }
730 16         40 return [$min, $max];
731             }
732              
733             ################################################################################
734             # sub vcol_file_process
735             # Description: read vcol_terms from file
736             #
737             ################################################################################
738             sub vcol_file_process
739             {
740 5     5 1 11467 my $self =shift;
741 5         9 my $file =shift;
742 5 50       224 open(VCOLFILE,$file) or carp "Couldnt open term file $file ";
743 5         212 my @cmp = ();
744 5         57 close(VCOLFILE);
745 5 50       23 @cmp=('') if $#cmp==-1;
746 5         23 map(chomp($_),@cmp);
747 5 50 66     35 if (exists $Data::Generate::vchain_type->{$self->{chain_type}}
748             && exists $Data::Generate::vchain_type->{$self->{chain_type}}->{check_type}
749             )
750             {
751 3         6 my @cmp2=();
752 3         7 foreach my $element (@cmp)
753             {
754             my $result=
755 19         25 &{$Data::Generate::vchain_type->{$self->{chain_type}}->{check_type}}
  19         51  
756             ($element);
757 19 100       420 push(@cmp2,$result) if defined $result;
758             }
759 3         11 @cmp=@cmp2;
760             };
761 5         9 my $uniq={};
762 5         29 map($uniq->{$_}++,@cmp);
763 5         20 @cmp=(keys %$uniq);
764 5         10 push(@{$self->{actual_vcol}->{value_term_list}},@cmp);
  5         114  
765             }
766              
767              
768              
769              
770             ################################################################################
771             # sub vcol_date_process
772             # Description: processing action for dates.
773             # At the end of each date production the three vcol date types year month day
774             # will be merged to a single one, so that date validity can be assessed,
775             # therefore instead of normally adding the date columns year and month,
776             # we keep them aside until the day column is processed.
777             #
778             ################################################################################
779             sub vcol_date_process
780             {
781 24     24 1 37 my $self =shift;
782 24 100       79 if ($self->{actual_vcol}->{type} =~ /^(month|year)$/ )
783             {
784 16         30 my $type=$self->{actual_vcol}->{type};
785 16         31 $type.='_vcol';
786 16         29 $self->{$type} = $self->{actual_vcol};
787 16         28 return;
788             }
789 8 50       25 die "internal eror" if ($self->{actual_vcol}->{type} ne 'day' );
790 8         16 $self->{day_vcol} = $self->{actual_vcol};
791 8         17 $self->{actual_vcol}={};
792 8         17 my @value_term_list=();
793 8         13 my $weekdays={};
794 8 100       34 if (exists $self->{day_vcol}->{weekday_term_list})
795             {
796 2         4 foreach my $day_term (@{$self->{day_vcol}->{weekday_term_list}})
  2         5  
797             {
798 6         17 $weekdays->{$day_term}++
799             }
800             }
801 8         13 foreach my $year_term (@{$self->{year_vcol}->{value_term_list}})
  8         22  
802             {
803 12         628 foreach my $month_term (@{$self->{month_vcol}->{value_term_list}})
  12         41  
804             {
805 28         2534 my $monthdays={};
806 28         39 foreach my $day_term (@{$self->{day_vcol}->{value_term_list}})
  28         59  
807             {
808             # convert 'char dates in numeric ones like '07'-> 7
809             # otherwise we cannot make unique value set
810 99         108 $day_term+=0;
811 99         172 $monthdays->{$day_term}++
812             }
813 28         83 my $first_month_weekday=dayofweek( 01,$month_term, $year_term );
814 28         903 foreach my $wkday_term (keys %{$weekdays})
  28         76  
815             {
816 24         37 my $day_term=$wkday_term-$first_month_weekday+1;
817 24 100       39 $day_term+=7 if $day_term<1;
818 24         45 while ($day_term<31)
819             {
820 104         165 $monthdays->{$day_term}++;
821 104         186 $day_term+=7;
822             }
823             }
824 28         43 foreach my $day_term (keys %{$monthdays})
  28         82  
825             {
826 200         27938 my $date_term =
827             sprintf('%04d%02d%02d',$year_term, $month_term, $day_term);
828 200 50       390 push(@value_term_list,$date_term)
829             if defined str2time($date_term);
830             }
831             }
832             }
833 8         1464 @value_term_list=sort(@value_term_list);
834 8         27 $self->{actual_vcol}->{value_term_list}=\@value_term_list;
835              
836 8         34 $self->add_value_column($self->{actual_vcol}->{value_term_list});
837 8         26 delete $self->{year_vcol};
838 8         23 delete $self->{month_vcol};
839 8         22 delete $self->{day_vcol};
840              
841             }
842              
843              
844             ################################################################################
845             # sub vchain_date_fraction_process
846             # Description: reorganizes the internal vchain structure of date types with
847             # fraction values due to the possible presence of trailing zeros.
848             ################################################################################
849             sub vchain_date_fraction_process
850             {
851            
852 2     2 1 6 my $self =shift;
853 2         4 my $vchain_full=$self->{actual_vchain};
854 2         6 $self->reset_actual_vchain();
855              
856 2         5 my $vchain_fraction={};
857 2         5 $vchain_fraction->{vcol_count}=$vchain_full->{vcol_count};
858             map($vchain_fraction->{vcol_hash}->{$_}->{value_column}=
859             $vchain_full->{vcol_hash}->{$_}->{value_column},
860 2         21 (0..$vchain_fraction->{vcol_count}));
861              
862              
863             my $fraction_start=
864             $Data::Generate::vchain_type->{DATE}->{subtype}->{'DATEWITHFRACTION'}
865 2         9 ->{fraction_start_ix};
866             map_vchain_indexes($vchain_fraction,
867 14 100   14   32 sub { return undef if $_[0] <$fraction_start;
868 6         11 return $vchain_fraction->{vcol_count}-$_[0];
869             }
870 2         20 );
871             $vchain_fraction->{vcol_count}=$vchain_full->{vcol_count}-
872 2         11 $fraction_start;
873              
874 2         3 my $vchain_data={};
875 2         5 $vchain_data->{weigth}=$vchain_full->{weigth};
876 2         7 my $vchain_weigth_list=$self->vchain_number_reprocess($vchain_fraction);
877              
878 2         5 foreach my $vchain (@$vchain_weigth_list)
879             {
880 8         13 $vchain->{vcol_count}+=$fraction_start;
881             map_vchain_indexes($vchain,
882 46     46   54 sub { return $vchain->{vcol_count}-$_[0];
883             }
884 8         24 );
885             map($vchain->{vcol_hash}->{$_}->{value_column}=
886             $vchain_full->{vcol_hash}->{$_}->{value_column},
887 8         39 (0..$fraction_start-1));
888             }
889              
890             # weigth has to be recalculated now.
891 2         7 calculate_vchain_list_weigth($vchain_weigth_list,$vchain_data->{weigth});
892              
893              
894 2         9 1;
895             }
896              
897              
898             ################################################################################
899             # sub vchain_fraction_process
900             # Description: reorganizes the internal vchain structure of a fractional
901             # vchain part due to the possible presence of trailing zeros.
902             ################################################################################
903             sub vchain_fraction_process
904             {
905            
906 8     8 1 16 my $self =shift;
907 8         17 my $vchain_fraction =$self->{actual_vchain};
908 8         25 $self->reset_actual_vchain();
909             map_vchain_indexes($vchain_fraction,
910             sub {
911 15     15   27 return $vchain_fraction->{vcol_count}-$_[0];
912             }
913 8         46 );
914 8         24 my $vchain_data={};
915 8         16 $vchain_data->{weigth}=$vchain_fraction->{weigth};
916 8         21 my $vchain_weigth_list=$self->vchain_number_reprocess($vchain_fraction);
917              
918 8         18 foreach my $vchain (@$vchain_weigth_list)
919             {
920             map_vchain_indexes($vchain,
921 20     20   36 sub { return $vchain->{vcol_count}-$_[0];
922             }
923 13         76 );
924             }
925 8         23 return $vchain_weigth_list;
926              
927              
928 0         0 1;
929             }
930              
931              
932             ################################################################################
933             # sub merge_vchain_float_lists
934             # Description: merge int and float vchain lists together.(and add a '.' inbet.)
935             ################################################################################
936             sub merge_vchain_float_lists
937             {
938 8     8 1 15 my $self =shift;
939 8         19 my $vchain_sign_list =shift;
940 8         14 my $vchain_integer_list =shift;
941 8         20 my $vchain_float_list =shift;
942 8         18 my $vchain_exp_list =shift;
943 8         14 my $vchain_merge_list =[];
944 8         15 my $vchain_zero =undef;
945 8         16 foreach my $vchain_integer (@$vchain_integer_list)
946             {
947 12     26   47 map_vchain_indexes($vchain_integer, sub { return 1+$_[0] ;});
  26         41  
948 12         38 $vchain_integer->{vcol_hash}->{0}->{value_column}=$vchain_sign_list;
949 12         29 $vchain_integer->{vcol_count}++;
950             }
951 8 50       28 if (@$vchain_exp_list ==0)
952             {
953 0         0 my $vchain_exp={};
954 0         0 $vchain_exp->{vcol_hash}->{0}->{value_column}=['0'];
955 0         0 $vchain_exp->{vcol_count}++;
956 0         0 push(@$vchain_exp_list,$vchain_exp);
957             }
958 8         22 foreach my $vchain_exp (@$vchain_exp_list)
959             {
960 8     9   31 map_vchain_indexes($vchain_exp, sub { return 1+$_[0] ;});
  9         14  
961 8         28 $vchain_exp->{vcol_hash}->{0}->{value_column}=['E'];
962 8         27 $vchain_exp->{vcol_count}++;
963             }
964 8         18 my $vchain_exp = $vchain_exp_list->[0];
965 8         19 foreach my $vchain_integer (@$vchain_integer_list)
966             {
967 12         24 foreach my $vchain_float (@$vchain_float_list)
968             {
969 25         37 foreach my $vchain_exp (@$vchain_exp_list)
970             {
971 25         44 my $vchain_merged={};
972 25         50 $vchain_merged->{vcol_count}=$vchain_integer->{vcol_count};
973             map($vchain_merged->{vcol_hash}->{$_}->{value_column}=
974             $vchain_integer->{vcol_hash}->{$_}->{value_column},
975 25         133 (0..$vchain_integer->{vcol_count}));
976 25         42 $vchain_merged->{vcol_count}++;
977 25         64 $vchain_merged->{vcol_hash}->{$vchain_merged->{vcol_count}}->{value_column}=['.'];
978              
979             map($vchain_merged->{vcol_hash}->{$vchain_merged->{vcol_count}+1+$_}
980             ->{value_column}=$vchain_float->{vcol_hash}->{$_}->{value_column},
981 25         137 (0..$vchain_float->{vcol_count}));
982 25         44 $vchain_merged->{vcol_count}+=$vchain_float->{vcol_count}+1;
983              
984              
985             # avoid double +/-0.0 , skip exp processing
986 25 100 100     101 if (($#{$vchain_merged->{vcol_hash}->{1}->{value_column}}==0)
  25   66     133  
      66        
      66        
      100        
      66        
987             && ($vchain_merged->{vcol_hash}->{1}->{value_column}->[0]==0)
988 6         29 && ($#{$vchain_merged->{vcol_hash}->{2}->{value_column}}==0)
989             && ($vchain_merged->{vcol_hash}->{2}->{value_column}->[0] eq '.')
990 6         30 && ($#{$vchain_merged->{vcol_hash}->{3}->{value_column}}==0)
991             && ($vchain_merged->{vcol_hash}->{3}->{value_column}->[0]==0)
992             && ($vchain_merged->{vcol_count}==3)
993             )
994             {
995 2 50       7 next if defined $vchain_zero;
996 2         12 $vchain_merged->{vcol_hash}->{0}->{value_column}=['+'];
997 2         14 $self->bind_vchain($vchain_merged);
998 2         4 push(@$vchain_merge_list,$vchain_merged);
999 2         4 $vchain_zero=$vchain_merged;
1000 2         5 next;
1001             }
1002              
1003              
1004              
1005             map($vchain_merged->{vcol_hash}->{$vchain_merged->{vcol_count}+1+$_}
1006             ->{value_column}=$vchain_exp->{vcol_hash}->{$_}->{value_column},
1007 23         120 (0..$vchain_exp->{vcol_count}));
1008 23         38 $vchain_merged->{vcol_count}+=$vchain_exp->{vcol_count}+1;
1009            
1010 23         50 $self->bind_vchain($vchain_merged);
1011 23         46 push(@$vchain_merge_list,$vchain_merged);
1012            
1013             }
1014             }
1015             }
1016 8         21 return $vchain_merge_list;
1017              
1018 0         0 1;
1019             }
1020              
1021              
1022              
1023              
1024             ################################################################################
1025             # sub vchain_date_fraction_process
1026             # Description: reorganizes the internal vchain structure of date types with
1027             # fraction values due to the possible presence of trailing zeros.
1028             ################################################################################
1029             sub vchain_float_process
1030             {
1031 26     26 1 37 my $self =shift;
1032 26 100       69 if ($self->{actual_vchain}->{chain_subtype} eq 'FLOATLIST' )
1033             {
1034 1         4 $self->bind_vchain($self->{actual_vchain});
1035 1         3 $self->reset_actual_vchain();
1036 1         1 return;
1037             }
1038              
1039 25 100       75 if ($self->{actual_vchain}->{chain_subtype} eq 'FLOATINTPART' )
1040             {
1041 8         16 $self->{FLOAT_CHAIN_START}=1+$#{$self->{vchain_array}};
  8         24  
1042 8         23 $self->{FLOAT_CHAIN_SIGN}=[];
1043 5         16 push (@{$self->{FLOAT_CHAIN_SIGN}},'+')
1044             if (! exists $self->{actual_vchain}->{sign}
1045 8 100 66     49 || exists $self->{actual_vchain}->{sign}->{'+'} );
1046 5         16 push (@{$self->{FLOAT_CHAIN_SIGN}},'-')
1047             if ( exists $self->{actual_vchain}->{sign}
1048 8 100 66     49 && exists $self->{actual_vchain}->{sign}->{'-'} );
1049              
1050 8         16 my $actual_vchain= $self->{actual_vchain};
1051 8         81 $self->reset_actual_vchain();
1052 8         25 $self->{FLOAT_INTEGER_PART}=$self->vchain_number_reprocess($actual_vchain);
1053 8         15 return;
1054              
1055             }
1056              
1057              
1058              
1059 17 100       42 if ($self->{actual_vchain}->{chain_subtype} eq 'FLOATFRACTION' )
1060             {
1061 8         29 $self->{FLOAT_FRACTION_PART}=$self->vchain_fraction_process();
1062 8         14 my $actual_vchain= $self->{actual_vchain};
1063 8         24 $self->reset_actual_vchain();
1064 8         17 return;
1065             }
1066 9 100       27 if ($self->{actual_vchain}->{chain_subtype} eq 'FLOATEXP' )
1067             {
1068 1         4 $self->{FLOAT_EXP_PART}=$self->vchain_integer_process();
1069 1         2 return;
1070             }
1071              
1072              
1073              
1074              
1075              
1076             croak "Error in float parsing $self->{actual_vchain}->{chain_subtype} "
1077 8 50       25 unless $self->{actual_vchain}->{chain_subtype} eq 'FLOATTOTAL';
1078             # print "*********************".$self->{actual_vchain}->{weigth}."\n";
1079 8         21 $self->{FLOAT_CHAIN_WEIGTH}=$self->{actual_vchain}->{weigth};
1080              
1081 8 100       48 unless (exists $self->{FLOAT_EXP_PART})
1082             {
1083 7         17 $self->{actual_vchain}->{chain_subtype}= 'FLOATEXP';
1084 7         13 push(@{$self->{actual_vcol}->{value_term_list}},0);
  7         21  
1085 7         35 $self->bind_actual_vcol();
1086 7         23 $self->{FLOAT_EXP_PART}=$self->vchain_integer_process();
1087 7         35 $self->{zzzzFLOAT_EXP_PART}=$self->{FLOAT_EXP_PART};
1088             }
1089              
1090 8         19 foreach my $vchain_id ($self->{FLOAT_CHAIN_START}..$#{$self->{vchain_array}})
  8         23  
1091             {
1092 33         65 delete $self->{vchain_hash}->{$vchain_id};
1093 33         38 pop(@{$self->{vchain_array}});
  33         49  
1094             }
1095             my $merge_list=$self->merge_vchain_float_lists($self->{FLOAT_CHAIN_SIGN},
1096             $self->{FLOAT_INTEGER_PART},
1097             $self->{FLOAT_FRACTION_PART},
1098 8         33 $self->{FLOAT_EXP_PART});
1099 8         22 calculate_vchain_list_weigth($merge_list,$self->{FLOAT_CHAIN_WEIGTH});
1100 8         17 delete $self->{FLOAT_CHAIN_START};
1101 8         13 delete $self->{FLOAT_CHAIN_SIGN};
1102 8         13 delete $self->{FLOAT_CHAIN_WEIGTH};
1103 8         48 delete $self->{FLOAT_INTEGER_PART};
1104 8         27 delete $self->{FLOAT_FRACTION_PART};
1105 8         16 delete $self->{FLOAT_EXP_PART};
1106              
1107 8         14 1;
1108             }
1109              
1110              
1111              
1112             ################################################################################
1113             # sub vchain_integer_process
1114             # Description: reorganizes the internal vchain structure of integer types.
1115             # due to the possible presence of leading zeros.
1116             ################################################################################
1117             # INT (9) +/- [3,0] [21,3,0] [4,0]
1118             #
1119             # + 0 0 4 -> converted to + 0 | + 3 0 4 | + 21 4| + 4
1120             # - 3 21 0 | - 21 0 | - 3 0| -
1121             # 3 | 3 | |
1122             # | | |
1123             #
1124             # degr of freedom = 1 + 12 + 8 + 2 = 23
1125             # -210','-214','-30','-300','-304','-3210','-3214','-330','-334','-34','-4','0','210','214','30','300',
1126             # '304','3210','3214
1127             sub vchain_integer_process
1128             {
1129            
1130 13     13 1 26 my $self =shift;
1131 13         20 my $last_vchain=$self->{actual_vchain};
1132 13         37 $self->reset_actual_vchain();
1133 13         22 my $vchain_data={};
1134 13         27 $vchain_data->{weigth}=$last_vchain->{weigth};
1135              
1136 11         35 push (@{$vchain_data->{sign}},'+')
1137 13 100 100     72 if (! exists $last_vchain->{sign} || exists $last_vchain->{sign}->{'+'} );
1138 3         7 push (@{$vchain_data->{sign}},'-')
1139 13 50 66     79 if ( exists $last_vchain->{sign} && exists $last_vchain->{sign}->{'-'} );
1140 13         25 delete $last_vchain->{sign};
1141 13         39 my $vchain_weigth_list=$self->vchain_number_reprocess($last_vchain);
1142              
1143 13         33 foreach my $vchain (@$vchain_weigth_list)
1144             {
1145             next if $vchain->{vcol_count}==0
1146 13         82 && @{$vchain->{vcol_hash}->{0}->{value_column}}==1
1147 19 100 100     68 && $vchain->{vcol_hash}->{0}->{value_column}->[0]==0;
      100        
1148 10     23   41 map_vchain_indexes($vchain,sub { return 1+$_[0];});
  23         55  
1149 10         23 $vchain->{vcol_count}++;
1150 10         14 @{$vchain->{vcol_hash}->{0}->{value_column}}=@{$vchain_data->{sign}};
  10         30  
  10         19  
1151             }
1152             # weigth has to be recalculated now.
1153 13         43 calculate_vchain_list_weigth($vchain_weigth_list,$vchain_data->{weigth});
1154 13         48 return $vchain_weigth_list;
1155             }
1156              
1157              
1158              
1159             ################################################################################
1160             # sub vchain_number_reprocess
1161             # Description: reorganizes the internal vchain structure of numeric types.
1162             # Due to the possible presence of leading or trailing zeros, we have to
1163             # restructure the vcols in vchains to avoid duplicates (001, 01 problem).
1164             # Other solutions are either too memory intensive (build the output values at
1165             # vchain binding) or lead to incorrect cardinality calculation (eliminate
1166             # duplicates at output data production);
1167             ################################################################################
1168             # INT (9) +/- [3,0] [21,3,0] [4,0]
1169             #
1170             # + 0 0 4 -> converted to + 0 | + 3 0 4 | + 21 4| + 4
1171             # - 3 21 0 | - 21 0 | - 3 0| -
1172             # 3 | 3 | |
1173             # | | |
1174             #
1175             # degr of freedom = 1 + 12 + 8 + 2 = 23
1176             # -210','-214','-30','-300','-304','-3210','-3214','-330','-334','-34','-4','0','210','214','30','300',
1177             # '304','3210','3214','330','334','34','4
1178             sub vchain_number_reprocess
1179             {
1180 31     31 1 54 my $self =shift;
1181 31         49 my $last_vchain =shift;
1182            
1183 31         47 my $vcol_nonzero_list=[];
1184 31         45 my $vcol_zero_list=[];
1185 31         45 my $vchain_weigth_list=[];
1186            
1187 31         116 while($last_vchain->{vcol_count}>=0)
1188             {
1189             my $vcol_list=
1190 46         75 $last_vchain->{vcol_hash}->{0}->{value_column};
1191            
1192 46         81 $vcol_nonzero_list=[];
1193 46         63 $vcol_zero_list=[];
1194 46         83 foreach my $vcol_value (@$vcol_list)
1195             {
1196 104 100       265 push (@$vcol_nonzero_list,$vcol_value) unless $vcol_value =~ /^0+$/;
1197 104 100       219 push (@$vcol_zero_list,$vcol_value) if $vcol_value =~ /^0+$/;
1198             }
1199 46 100       101 if(@$vcol_nonzero_list >0)
1200             {
1201             $last_vchain->{vcol_hash}->{0}->{value_column}
1202 36         56 =$vcol_nonzero_list;
1203 36         108 $self->bind_vchain($last_vchain);
1204             push(@$vchain_weigth_list,$self->{vchain_hash}
1205 36         69 ->{$#{$self->{vchain_array}}});
  36         68  
1206             }
1207 46 100       112 last unless(@$vcol_zero_list>0);
1208 31         67 my $next_vchain={};
1209 31         59 $next_vchain->{vcol_count}=$last_vchain->{vcol_count};
1210             map($next_vchain->{vcol_hash}->{$_}->{value_column}=
1211             $last_vchain->{vcol_hash}->{$_}->{value_column},
1212 31         133 (0..$last_vchain->{vcol_count}));
1213             map_vchain_indexes($next_vchain,sub {
1214 51 100   51   122 return undef if $_[0]==0;
1215 20         28 return $_[0]-1;
1216 31         189 });
1217 31         80 $next_vchain->{vcol_count}--;
1218 31         69 $last_vchain=$next_vchain;
1219             }
1220 31 100       73 if (@$vcol_zero_list>0)
1221             {
1222             # add now 0 chain in place of +/-
1223 16         39 $last_vchain->{vcol_hash}->{0}->{value_column}=[0];
1224 16         28 $last_vchain->{vcol_count}++;
1225 16         70 $self->bind_vchain($last_vchain);
1226             push(@$vchain_weigth_list,$self->{vchain_hash}
1227 16         33 ->{$#{$self->{vchain_array}}});
  16         33  
1228             }
1229 31         94 return $vchain_weigth_list;
1230             }
1231              
1232             ################################################################################
1233             # Description: helper function. Calculate weigth for a group of vchains
1234             ################################################################################
1235             sub calculate_vchain_list_weigth
1236             {
1237 23     23 1 33 my $vchain_list =shift;
1238 23         36 my $weigth =shift;
1239 23         60 my $card=
1240             calculate_vchain_list_degrees_of_freedom($vchain_list);
1241 23         74 map($_->{weigth}=$weigth,@$vchain_list);
1242 23         70 map($_->{weigth}*=$_->{vchain_card},@$vchain_list);
1243 23         64 map($_->{weigth}/=$card,@$vchain_list);
1244             }
1245              
1246             ################################################################################
1247             # Description: helper function.Change internal vcol indexes of a vchain
1248             ################################################################################
1249             sub map_vchain_indexes
1250             {
1251 92     92 1 115 my $vchain =shift;
1252 92         101 my $change_function =shift;
1253 92         169 foreach my $index (0..$vchain->{vcol_count})
1254             {
1255 204         317 my $new_index=&$change_function($index);
1256 204 100       368 next unless defined $new_index;
1257             $vchain->{vcol_hash_tmp}->{$new_index}->{value_column}=
1258 165         502 $vchain->{vcol_hash}->{$index}->{value_column};
1259             }
1260 92         220 $vchain->{vcol_hash}=$vchain->{vcol_hash_tmp};
1261 92         158 delete $vchain->{vcol_hash_tmp};
1262             }
1263              
1264              
1265             ################################################################################
1266             # Description: helper function
1267             ################################################################################
1268             sub check_input_limits
1269             {
1270 101     101 1 118 my $type =shift;
1271 101         119 my $value =shift;
1272            
1273             # no type defined, no ranges to check
1274 101 50       171 return unless defined $type;
1275 101 100       195 return unless exists $Data::Generate::vcol_type->{$type};
1276              
1277 85         109 my $limit_check_hash=$Data::Generate::vcol_type->{$type};
1278 85 50 33     268 if ((exists $limit_check_hash->{lowlimit}) &&
1279             (defined $limit_check_hash->{lowlimit}))
1280             {
1281             croak " $limit_check_hash->{type} went out of range,".
1282             " $value < $limit_check_hash->{lowlimit} "
1283 85 50       200 if $value < $limit_check_hash->{lowlimit};
1284             }
1285 85 50 33     227 if ((exists $limit_check_hash->{highlimit}) &&
1286             (defined $limit_check_hash->{highlimit}))
1287             {
1288             croak " $limit_check_hash->{type} went out of range,".
1289             " $value > $limit_check_hash->{highlimit} "
1290 85 50       170 if $value > $limit_check_hash->{highlimit};
1291             }
1292             }
1293              
1294              
1295             ################################################################################
1296             # sub # vcol_add_term_range
1297             # Description:
1298             # add an expression (a..b) after parsing
1299             ################################################################################
1300             sub add_weekday_term_range
1301             {
1302 2     2 1 5015 my $self =shift;
1303 2         5 my $min =shift;
1304 2         4 my $max =shift;
1305 2         3 my $act_vcol=$self->{actual_vcol};
1306 2 50       7 if ($min>$max)
1307             {
1308             # index 6 is sunday
1309 0         0 push(@{$self->{actual_vcol}->{weekday_term_list}},($min..6));
  0         0  
1310             # index 0 is monday
1311 0         0 push(@{$self->{actual_vcol}->{weekday_term_list}},(0..$max));
  0         0  
1312 0         0 return;
1313             }
1314 2         4 push(@{$self->{actual_vcol}->{weekday_term_list}},($min..$max));
  2         34  
1315             }
1316              
1317              
1318             ################################################################################
1319             # sub # vcol_add_term_range
1320             # Description:
1321             # add an expression (a..b) after parsing
1322             ################################################################################
1323             sub add_term_range
1324             {
1325 16     16 1 15524 my $self =shift;
1326 16         25 my $min =shift;
1327 16         18 my $max =shift;
1328 16         39 my $minmax=check_range_order($min,$max);
1329 16         28 my $act_vcol=$self->{actual_vcol};
1330 16         22 push(@{$self->{actual_vcol}->{value_term_list}},
  16         280  
1331             ($minmax->[0]..$minmax->[1]));
1332             }
1333              
1334              
1335             ################################################################################
1336             # sub # add_value_column_range
1337             # Description:
1338             # add an expression (a..b) after parsing
1339             ################################################################################
1340             sub bind_vcol_range
1341             {
1342 21     21 1 11260 my $self =shift;
1343 21         37 my $type =shift;
1344 21         30 my $act_vcol=$self->{actual_vcol};
1345 21         28 foreach my $value (@{$self->{actual_vcol}->{value_term_list}})
  21         53  
1346             {
1347 74         107 check_input_limits($type,$value);
1348             }
1349 21         34 $act_vcol->{type}=$type;
1350 21         46 $self->bind_actual_vcol();
1351             }
1352              
1353              
1354              
1355             ################################################################################
1356             # sub # add_value_column_range
1357             # Description:
1358             # add an expression (a..b) after parsing
1359             ################################################################################
1360             sub bind_vcol_literal
1361             {
1362 27     27 1 21096 my $self =shift;
1363 27         140 my $type =shift;
1364 27         42 my $act_vcol=$self->{actual_vcol};
1365 27         66 check_input_limits($type,$self->{actual_vcol}->{literal_value});
1366             $self->{actual_vcol}->{value_term_list}=
1367 27         56 [$act_vcol->{literal_value}];
1368 27         43 $act_vcol->{type}=$type;
1369 27         56 $self->bind_actual_vcol();
1370             }
1371              
1372              
1373             ################################################################################
1374             # sub # sub set_actual_vchain_weigth
1375             # Description:
1376             # add weigth to actual value chain
1377             ################################################################################
1378             sub reset_actual_vchain
1379             {
1380 90     90 1 122 my $self =shift;
1381 90         198 $self->{actual_vchain} = {};
1382 90         160 $self->{actual_vchain}->{vchain_length} = 0;
1383 90         434 $self->{actual_vchain}->{weigth}=100;
1384             }
1385              
1386             ################################################################################
1387             # sub bind_actual_vcol
1388             # Description: Postprocessing action.
1389             # At the end of each value column production, add actual value column to the
1390             # actual vchain. Afterwards reset actual_vcol to an empty hash
1391             #
1392             ################################################################################
1393             sub bind_actual_vcol
1394             {
1395 123     123 1 97020 my $self =shift;
1396 123         167 my $quantifier=1;
1397             $quantifier=$self->{actual_vcol}->{quantifier}
1398 123 100       317 if exists $self->{actual_vcol}->{quantifier};
1399            
1400              
1401 123 100 100     676 if ((defined $self->{actual_vcol}->{type} ) &&
    50 66        
1402             ($self->{actual_vcol}->{type} =~ /^(day|month|year)$/ ))
1403             {
1404 24         62 $self->vcol_date_process();
1405             }
1406             elsif ((defined $self->{actual_vcol}->{type} ) &&
1407             ($self->{actual_vcol}->{type} eq 'sign' ))
1408             {
1409 0         0 $self->{sign_value_list}=$self->{actual_vcol}->{value_term_list};
1410 0         0 $self->reset_actual_vcol();
1411             }
1412             else
1413             {
1414             $self->add_value_column($self->{actual_vcol}->{value_term_list})
1415 99         410 foreach(1..$quantifier);
1416             }
1417 123         278 $self->{actual_vcol} = {};
1418 123         2103 $self->{actual_vcol}->{type} = undef;
1419             }
1420              
1421             sub reset_actual_vcol
1422             {
1423 0     0 1 0 my $self =shift;
1424 0         0 $self->{actual_vcol} = {};
1425 0         0 $self->{actual_vcol}->{type} = undef;
1426             }
1427              
1428              
1429             ################################################################################
1430             # Description: helper function. add vchain to generator object
1431             ################################################################################
1432             sub bind_vchain
1433             {
1434 99     99 1 134 my $self =shift;
1435 99         118 my $vchain =shift;
1436 99         127 push(@{$self->{vchain_array}},$vchain);
  99         182  
1437             $self->{vchain_hash}
1438 99         133 ->{$#{$self->{vchain_array}}}=$vchain;
  99         251  
1439             }
1440              
1441              
1442             ################################################################################
1443             # sub bind_actual_vchain
1444             # Description: Postprocessing action.
1445             # At the end of each chain production, add actual value chain to the chain list
1446             # root structure, and afterwards reset actual_vchain to an empty hash
1447             #
1448             ################################################################################
1449             sub bind_actual_vchain
1450             {
1451 54     54 1 53320 my $self =shift;
1452 54 100       163 if ($self->{chain_type} eq 'INTEGER')
1453             {
1454 5         21 $self->vchain_integer_process();
1455 5         103 return;
1456             }
1457 49 100 100     195 if ((exists $self->{actual_vchain}->{chain_subtype})
1458             && ($self->{actual_vchain}->{chain_subtype} eq 'DATEWITHFRACTION'))
1459             {
1460 2         37 $self->vchain_date_fraction_process();
1461 2         44 return;
1462             }
1463 47 100       111 if ($self->{chain_type} eq 'FLOAT')
1464             {
1465 26         77 $self->vchain_float_process();
1466 26         488 return;
1467             }
1468 21         87 $self->bind_vchain($self->{actual_vchain});
1469 21         56 $self->reset_actual_vchain();
1470             }
1471              
1472             ################################################################################
1473             # sub add_value_column
1474             # Description:
1475             # add array of terms.
1476             #
1477             ################################################################################
1478             sub add_value_column
1479             {
1480 136     136 1 191 my $self = shift;
1481 136         152 my $tmp_value_column = shift;
1482 136         201 my $value_column = [];
1483 136         228 my $vcol_maxlength=0;
1484 136         162 my $ix=0;
1485 136         170 my $unique={};
1486 136         173 foreach my $value_term (@{$tmp_value_column})
  136         225  
1487             {
1488 787         912 my $vterm_length=length($value_term);
1489 787 100 66     3400 if (exists $self->{ct_length} && defined $self->{ct_length} &&
    100 100        
1490             $self->{actual_vchain}->{vchain_length}+ $vterm_length>$self->{ct_length})
1491             {
1492 1         190 carp "Maximal length for type $self->{chain_type}($self->{ct_length}) "
1493             ."exceeded for \n$self->{vchain_text}\n"
1494             ."Element \'$value_term\' will be removed from output structures.\n"
1495             ."Please check your data creation rules\n";
1496 1         86 next;
1497             }
1498             elsif ($unique->{$value_term}++>0)
1499             {
1500 2         238 carp "Duplicate entry \'$value_term\' found while building up internal structures.\n"
1501             ."Element \'$value_term\' will be removed from output structures.\n"
1502             ."Please check your data creation rules\n";
1503 2         126 next;
1504             }
1505             else
1506             {
1507 784         875 push(@{$value_column},$value_term);
  784         1145  
1508 784 100       1065 $vcol_maxlength =($vterm_length>$vcol_maxlength?$vterm_length:$vcol_maxlength);
1509 784         931 $ix++;
1510             }
1511             };
1512 136         240 $self->{actual_vchain}->{vchain_length}+=$vcol_maxlength;
1513 136 100       163 if ($#{$value_column}==-1)
  136         322  
1514             {
1515 1         4 return 1;
1516             }
1517              
1518 135 100       255 if (exists $self->{actual_vchain}->{vcol_count})
1519             {
1520            
1521 82         120 $self->{actual_vchain}->{vcol_count}++
1522             }
1523             else
1524 53         97 {$self->{actual_vchain}->{vcol_count}=0}
1525            
1526 135         636 $self->{actual_vchain}->{vcol_hash}->{$self->{actual_vchain}->{vcol_count}}->{value_column} = $value_column;
1527             }
1528              
1529              
1530              
1531             ################################################################################
1532             # sub get_value_column_reverse
1533             # Description: fill array in place with complementary ascii chars
1534             #
1535             ################################################################################
1536             sub get_value_column_reverse {
1537 1     1 1 2 my $self = shift;
1538 1         1 my $value_column = shift;
1539 1         76 my @complement = map(chr,(0..255));
1540 1         3 my $hash={};
1541 1         1 $hash->{$_}++ foreach (@{$value_column});
  1         43  
1542 1         2 $value_column=[];
1543 1         3 foreach (@complement)
1544             {
1545 256 100       379 push(@$value_column,$_) unless $hash->{$_};
1546             }
1547 1         20 return $value_column;
1548             }
1549              
1550              
1551             ################################################################################
1552             # sub get_occupation_ratio
1553             # Description:
1554             # Based on input cardinality and degrees of freedom calculate
1555             # the ratio of array elements to give / total number of elements
1556             #
1557             ################################################################################
1558             sub set_occupation_ratio
1559             {
1560 54     54 1 67 my $self = shift;
1561 54         72 foreach my $actual_vchain (@{$self->{vchain_array}})
  54         91  
1562             {
1563 121         139 my $occupation_ratio = 0;
1564             $occupation_ratio =
1565             log($actual_vchain->{data_card}/$actual_vchain->{vchain_card})
1566 121         268 / ($actual_vchain->{vcol_count}+1);
1567 121         179 $occupation_ratio =exp($occupation_ratio);
1568 121         210 $actual_vchain->{vchain_occupation_ratio}= $occupation_ratio;
1569             }
1570             }
1571              
1572              
1573              
1574             ################################################################################
1575             # sub calculate_occupation_levels
1576             # Description:
1577             # based on input cardinality calculate occupation levels.
1578             #
1579             ################################################################################
1580             sub calculate_occupation_levels
1581             {
1582 54     54 1 70 my $self = shift;
1583 54         66 my $data_card = shift;
1584 54         122 $self->check_input_card($data_card);
1585 54         127 $self->set_occupation_ratio();
1586 54         67 foreach my $actual_vchain (@{$self->{vchain_array}})
  54         86  
1587             {
1588 121         147 my $vchain_occupation_ratio =$actual_vchain->{vchain_occupation_ratio};
1589 121         128 foreach (values %{$actual_vchain->{vcol_hash}})
  121         231  
1590             {
1591 568         596 my $vcol_degrees_of_freedom =$#{$_->{value_column}}+1;
  568         716  
1592 568 100       781 if ($vchain_occupation_ratio ==1)
1593 271         357 { $_->{occupation_level} = $vcol_degrees_of_freedom }
1594             else
1595             {
1596             $_->{occupation_level} =
1597 297         466 int($vchain_occupation_ratio*$vcol_degrees_of_freedom)+1;
1598             }
1599             }
1600             }
1601 54         79 return ;
1602             }
1603              
1604              
1605             ################################################################################
1606             # sub get_degrees_of_freedom
1607             # Description:
1608             # get maximal cardinality
1609             #
1610             ################################################################################
1611             sub get_degrees_of_freedom
1612             {
1613 29     29 1 16326 my $self = shift;
1614 29         49 my $weigthed_card=undef;
1615 29         81 foreach my $vchain_ref (@{$self->{vchain_array}})
  29         68  
1616             {
1617             confess " weigth undefined " unless defined $vchain_ref->{weigth} &&
1618 66 50 33     243 defined $vchain_ref->{vchain_card};
1619 66 50       140 if ($vchain_ref->{weigth} >0.0001)
1620             {
1621             $vchain_ref->{weigthed_card}=$vchain_ref->{vchain_card}/
1622 66         131 $vchain_ref->{weigth};
1623             }
1624             else
1625             {
1626 0         0 $vchain_ref->{weigthed_card}=10000
1627             }
1628 66 50       127 $vchain_ref->{weigthed_card}=1 if $vchain_ref->{weigthed_card}<1;
1629             $weigthed_card = $vchain_ref->{weigthed_card}
1630 66 100       137 unless defined $weigthed_card;
1631             $weigthed_card = $vchain_ref->{weigthed_card}
1632 66 100       129 if $weigthed_card > $vchain_ref->{weigthed_card} ;
1633             }
1634            
1635             # workaround to handle integers numbers converted to float and back
1636 29 100       81 if ( int($weigthed_card)+1-$weigthed_card <1e-9)
1637             {
1638 1         4 return int($weigthed_card)+1;
1639             }
1640 28         57 return int($weigthed_card);
1641             }
1642              
1643              
1644              
1645              
1646             ################################################################################
1647             # sub calculate_vchain_list_degrees_of_freedom
1648             # Description:
1649             # calculate maximal cardinality for a vchain
1650             #
1651             ################################################################################
1652             sub calculate_vchain_list_degrees_of_freedom
1653             {
1654 52     52 1 75 my $vchain_list = shift;
1655 52         65 my $card=0;
1656 52         84 foreach my $vchain_ref (@$vchain_list)
1657             {
1658 118         153 $vchain_ref->{vchain_card}=1;
1659 118         147 foreach my $vcol_ref (values %{$vchain_ref->{vcol_hash}})
  118         272  
1660 591         634 { $vchain_ref->{vchain_card}*=$#{$vcol_ref->{value_column}}+1 }
  591         870  
1661 118         157 $card+=$vchain_ref->{vchain_card};
1662             }
1663 52         83 return $card;
1664             }
1665              
1666              
1667             ################################################################################
1668             # sub calculate_degrees_of_freedom
1669             # Description:
1670             # calculate maximal cardinality of the generation rules
1671             #
1672             ################################################################################
1673             sub calculate_degrees_of_freedom
1674             {
1675 29     29 1 37 my $self = shift;
1676             $self->{card}=
1677 29         64 calculate_vchain_list_degrees_of_freedom($self->{vchain_array});
1678 29         46 return $self->{card};
1679             }
1680              
1681              
1682             ################################################################################
1683             # sub calculate_weigth
1684             # Description:
1685             # normalize weigth so that total is 100%
1686             #
1687             ################################################################################
1688             sub calculate_weigth
1689             {
1690 29     29 1 37 my $self = shift;
1691 29         43 my $weigth=0.0;
1692 29         40 foreach my $vchain_ref (@{$self->{vchain_array}})
  29         59  
1693             {
1694 66         113 $weigth+= $vchain_ref->{weigth};
1695             }
1696 29         39 foreach my $vchain_ref (@{$self->{vchain_array}})
  29         59  
1697             {
1698 66         105 $vchain_ref->{weigth}/=$weigth
1699             }
1700             }
1701              
1702              
1703             ################################################################################
1704             # sub check_input_card
1705             # Description:
1706             # ensures that degrees of freedom >= input_card
1707             # generates a warning when input_card is bigger
1708             #
1709             ################################################################################
1710             sub check_input_card
1711             {
1712 54     54 1 74 my $self = shift;
1713 54         70 my $data_card = shift;
1714 54 100       142 if ($data_card > $self->{card})
1715             {
1716             carp "Input card ".$data_card." too big, maximal nr of ".
1717             "values is $self->{card}.\nReturn only ".
1718 2         264 $self->{card} ." values. \n";
1719 2         144 $data_card=$self->{card};
1720             }
1721              
1722 54         69 foreach my $vchain_ref (@{$self->{vchain_array}})
  54         108  
1723             {
1724 121         168 $vchain_ref->{data_card}=$data_card;
1725 121         166 $vchain_ref->{data_card}*=$vchain_ref->{weigth};
1726             # $vchain_ref->{data_card}=int($vchain_ref->{data_card});
1727             # $vchain_ref->{data_card}=1 if $vchain_ref->{data_card}==0;
1728 121 50       288 if (int($vchain_ref->{data_card}) >$vchain_ref->{vchain_card})
1729             {
1730             carp "Either input card ".$data_card." too big or vchain weigth ".
1731             "$vchain_ref->{weigth} too high.\nShould produce ".
1732             $vchain_ref->{data_card}." values, can't produce more than ".
1733             $vchain_ref->{vchain_card}." different values.\nReturn only ".
1734 0         0 $vchain_ref->{vchain_card} ." values. \n";
1735 0         0 $vchain_ref->{data_card}=$vchain_ref->{vchain_card};
1736             }
1737             }
1738             }
1739              
1740             ################################################################################
1741             # sub fisher_yates_shuffle
1742             # Description: create a randomized array order. From Perl Cookbook
1743             #
1744             ################################################################################
1745             # fisher_yates_shuffle( \@array ) : generate a random permutation
1746             # of @array in place
1747             sub fisher_yates_shuffle {
1748 54     54 1 74 my $array = shift;
1749 54         65 my $i;
1750 54         124 for ($i = @$array; --$i; ) {
1751 3799         4401 my $j = int rand ($i+1);
1752 3799 100       4992 next if $i == $j;
1753 3691         6604 @$array[$i,$j] = @$array[$j,$i];
1754             }
1755             }
1756              
1757              
1758              
1759             ################################################################################
1760             # sub is_valid
1761             # Description: check if generator structure was built up successfully
1762             #
1763             ################################################################################
1764             sub is_valid {
1765 29     29 1 53 my $self = shift;
1766 29 50       60 return undef if @{$self->{vchain_array}} ==0;
  29         80  
1767 29         73 1;
1768             }
1769              
1770              
1771              
1772             ################################################################################
1773             # sub get_data
1774             # Description:
1775             # get data
1776             #
1777             ################################################################################
1778             sub get_unique_data
1779             {
1780 54     54 1 24958 my $self = shift;
1781 54         83 my $data_card =shift;
1782 54         142 $self->calculate_occupation_levels($data_card);
1783 54         83 my $data =[];
1784 54         94 my $chain_type=$self->{chain_type};
1785 54         63 foreach my $actual_vchain (@{$self->{vchain_array}})
  54         92  
1786             {
1787 121         185 my $tmpdata =[''];
1788 121         232 foreach my $value_column_index (0..$actual_vchain->{vcol_count})
1789             {
1790 568         850 my $value_column=$actual_vchain->{vcol_hash}->{$value_column_index};
1791 568         634 my @tmp_value_column_copy=@{$value_column->{value_column}};
  568         1443  
1792 568         665 my @value_column_array =();
1793 568         933 while(@value_column_array<$value_column->{occupation_level})
1794             {
1795 1354         1953 my $rnd_index=int(rand(@tmp_value_column_copy));
1796 1354         2482 push(@value_column_array,splice(@tmp_value_column_copy,$rnd_index,1));
1797             }
1798 568         647 my $format=undef;
1799             $format=
1800             $Data::Generate::vchain_type->{$chain_type}->{vcol_output_format}
1801             ->[$value_column_index]
1802             if ((exists $Data::Generate::vchain_type->{$chain_type})
1803             && (exists $Data::Generate::vchain_type
1804 568 100 100     1464 ->{$chain_type}->{vcol_output_format}));
1805             $tmpdata=vcol_chain($tmpdata, \@value_column_array,
1806 568         845 $actual_vchain->{data_card},$format);
1807              
1808             }
1809 121         867 push(@$data,@$tmpdata);
1810             }
1811             # makes a random order
1812 54         129 fisher_yates_shuffle($data);
1813             # take away too much produced data
1814 54         128 shift(@$data) while(@$data>$data_card);
1815             map($_=&{$Data::Generate::vchain_type
1816 3189         4642 ->{$chain_type}->{output_format_fct}}($_),@$data)
1817             if ((exists $Data::Generate::vchain_type->{$chain_type})
1818             && (exists $Data::Generate::vchain_type
1819 54 100 100     200 ->{$chain_type}->{output_format_fct}));
1820 54 100       225 @$data = map(int($_),@$data) if $chain_type eq 'INTEGER';
1821 54         9974 @$data = sort(@$data);
1822 54         95 my $uniq=[];
1823 54         74 my $last='';
1824 54         76 my $duplicates=0;
1825 54         84 foreach my $item (@$data) {
1826 3836 50       6172 if ($last eq $item)
1827             {
1828 0         0 $duplicates++;
1829 0         0 next;
1830             }
1831 3836         4319 push(@$uniq, $item);
1832 3836         4313 $last=$item;
1833             }
1834 54 50       98 carp "$duplicates duplicates found while generating ouput values.\n"
1835             ."Check syntax of statements" if $duplicates>0;
1836 54         668 return $uniq;
1837             }
1838              
1839              
1840             ################################################################################
1841             # sub vcol_chain
1842             # Description:
1843             # make a cross product of two value columns and concatenate the values.
1844             # if type is with formatted output prepare values with a pipe inbetween.
1845             #
1846             ################################################################################
1847             sub vcol_chain
1848             {
1849 568     568 1 587 my @original=@{shift()};
  568         1276  
1850 568         638 my @added =@{shift()};
  568         853  
1851 568         659 my $card=shift;
1852 568         609 my $format=shift;
1853 568 100       869 $format= "%s" unless defined $format;
1854 568         614 my @composed =();
1855 568         744 foreach my $ele (@added)
1856             {
1857            
1858 1258         1423 foreach my $e2 (@original)
1859             {
1860 9090         14066 push(@composed,$e2.sprintf($format,$ele));
1861 9090 50       11859 next unless defined $card;
1862 9090 100       14505 return \@composed if(@composed>=$card);
1863             }
1864             }
1865 175         408 return \@composed;
1866              
1867             };
1868              
1869              
1870              
1871              
1872              
1873              
1874             ################################################################################
1875             # sub parse
1876             # Description:
1877             # parse given text.
1878             # return either an error or a Data::Generate object
1879             #
1880             ################################################################################
1881             sub parse($)
1882             {
1883 29     29 1 25843 my ($text) = @_;
1884            
1885             # check that parser is up and running
1886 29 100       91 $Data::Generate::Parser=load_parser()
1887             unless (defined $Data::Generate::Parser);
1888              
1889              
1890             # create a new generator and set it as global for parse routines
1891 29         47 $Data::Generate::ACTUAL_VALUE_COLUMN=undef;
1892 29         46 $Data::Generate::VC_RANGE_REVERSE_FLAG=undef;
1893              
1894              
1895 29         97 $Data::Generate::current= Data::Generate->new($text);
1896 29         240 $Data::Generate::Parser->start($text);
1897 29 50       5471 $Data::Generate::current->is_valid() or
1898             croak "Error in parsing, invalid generator for $text";
1899 29         83 $Data::Generate::current->calculate_weigth();
1900 29         75 $Data::Generate::current->calculate_degrees_of_freedom();
1901 29         70 return $Data::Generate::current;
1902             }
1903              
1904              
1905              
1906              
1907             1;
1908              
1909              
1910             __END__