| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Randomize; | 
| 2 |  |  |  |  |  |  |  | 
| 3 |  |  |  |  |  |  | =head1 NAME | 
| 4 |  |  |  |  |  |  |  | 
| 5 |  |  |  |  |  |  | Randomize - Perl extension for randomizing things. | 
| 6 |  |  |  |  |  |  |  | 
| 7 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 8 |  |  |  |  |  |  |  | 
| 9 |  |  |  |  |  |  | use Randomize; | 
| 10 |  |  |  |  |  |  | my $randomizer = Randomize->new(\@rules); | 
| 11 |  |  |  |  |  |  | print "There are ", $randomizer->permutations(), | 
| 12 |  |  |  |  |  |  | " different possible outcomes.\n"; | 
| 13 |  |  |  |  |  |  | while (1) { | 
| 14 |  |  |  |  |  |  | my $random_hash = $randomizer->generate(); | 
| 15 |  |  |  |  |  |  | } | 
| 16 |  |  |  |  |  |  |  | 
| 17 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 18 |  |  |  |  |  |  |  | 
| 19 |  |  |  |  |  |  | This packages takes a set of randomization rules in the form of an | 
| 20 |  |  |  |  |  |  | array reference, and creates random hashes on request based on | 
| 21 |  |  |  |  |  |  | the rules given. | 
| 22 |  |  |  |  |  |  |  | 
| 23 |  |  |  |  |  |  | I know that doesn't make sense, so here's an example. | 
| 24 |  |  |  |  |  |  |  | 
| 25 |  |  |  |  |  |  | my @randomizer_rules = | 
| 26 |  |  |  |  |  |  | [ {Field  => 'Street', | 
| 27 |  |  |  |  |  |  | Values => [{Data   => ['Preston', 'Hillcrest'], | 
| 28 |  |  |  |  |  |  | Weight => 1}, | 
| 29 |  |  |  |  |  |  | {Data   => ['Coit'], | 
| 30 |  |  |  |  |  |  | Weight => 2}]}, | 
| 31 |  |  |  |  |  |  | {Field  => 'Number', | 
| 32 |  |  |  |  |  |  | Values => [18100..18299]} | 
| 33 |  |  |  |  |  |  | }; | 
| 34 |  |  |  |  |  |  |  | 
| 35 |  |  |  |  |  |  | my $randomizer = Randomize->new(\@randomizer_rules); | 
| 36 |  |  |  |  |  |  | while (1) | 
| 37 |  |  |  |  |  |  | my $hashref = $randomizer->generate(); | 
| 38 |  |  |  |  |  |  | } | 
| 39 |  |  |  |  |  |  |  | 
| 40 |  |  |  |  |  |  | The key is @randomizer_rules.  What this list tells Randomizer is that, | 
| 41 |  |  |  |  |  |  | every time you invoke the generate() method, you want to get back a reference | 
| 42 |  |  |  |  |  |  | to a hash that looks like: | 
| 43 |  |  |  |  |  |  |  | 
| 44 |  |  |  |  |  |  | $hashref = { Street => 'Preston', | 
| 45 |  |  |  |  |  |  | Number => 18111 }; | 
| 46 |  |  |  |  |  |  |  | 
| 47 |  |  |  |  |  |  | where the Number is between 18100 and 18299 and the Street is either Preston, | 
| 48 |  |  |  |  |  |  | Hillcrest, or Coit.  Further, you want the numbers to be evenly distributed, | 
| 49 |  |  |  |  |  |  | but you want the street to be Coit half the time, and evenly distributed | 
| 50 |  |  |  |  |  |  | between Preston and Hillcrest the rest of the time. | 
| 51 |  |  |  |  |  |  |  | 
| 52 |  |  |  |  |  |  | So, if you called $randomizer->generate() 1000 times, you'd get roughly | 
| 53 |  |  |  |  |  |  | 500 addresses on Coit and 250 addresses each on Preston and Hillcrest. | 
| 54 |  |  |  |  |  |  |  | 
| 55 |  |  |  |  |  |  | Let's look at a more complicated @randomizer_rules now. | 
| 56 |  |  |  |  |  |  |  | 
| 57 |  |  |  |  |  |  | my @randomizer_rules = | 
| 58 |  |  |  |  |  |  | ( {Field  => 'Street', | 
| 59 |  |  |  |  |  |  | Values => [{Data   => ['Preston', 'Hillcrest'], | 
| 60 |  |  |  |  |  |  | Weight => 1}, | 
| 61 |  |  |  |  |  |  | {Data   => ['Coit'], | 
| 62 |  |  |  |  |  |  | Weight => 2}]}, | 
| 63 |  |  |  |  |  |  | {Field  => 'Number', | 
| 64 |  |  |  |  |  |  | Values => [{Precondition => "<> eq 'Preston'", | 
| 65 |  |  |  |  |  |  | Alternatives => [{Data => [18100..18199], | 
| 66 |  |  |  |  |  |  | Weight => 1}, | 
| 67 |  |  |  |  |  |  | {Data => [18200..18299], | 
| 68 |  |  |  |  |  |  | Weight => 9}]}, | 
| 69 |  |  |  |  |  |  | {Precondition    => 'DEFAULT', | 
| 70 |  |  |  |  |  |  | Alternatives => [{Data => [18100..18299], | 
| 71 |  |  |  |  |  |  | Weight => 1}]}]} | 
| 72 |  |  |  |  |  |  | ); | 
| 73 |  |  |  |  |  |  |  | 
| 74 |  |  |  |  |  |  | Given this, the generate() method will still return a hash reference in | 
| 75 |  |  |  |  |  |  | the form | 
| 76 |  |  |  |  |  |  |  | 
| 77 |  |  |  |  |  |  | $hashref = { Street => 'Preston', | 
| 78 |  |  |  |  |  |  | Number => 18111 }; | 
| 79 |  |  |  |  |  |  |  | 
| 80 |  |  |  |  |  |  | with the same streets and address ranges.  However, if the street | 
| 81 |  |  |  |  |  |  | picked happens to be Preston, 90% of the addresses generated | 
| 82 |  |  |  |  |  |  | will be in the range 18200 to 18299. | 
| 83 |  |  |  |  |  |  |  | 
| 84 |  |  |  |  |  |  | In final example, note the Retry_If clause: | 
| 85 |  |  |  |  |  |  |  | 
| 86 |  |  |  |  |  |  | my @randomizer_rules = | 
| 87 |  |  |  |  |  |  | ( {Field  => 'Street', | 
| 88 |  |  |  |  |  |  | Values => [{Data   => ['Preston', 'Hillcrest'], | 
| 89 |  |  |  |  |  |  | Weight => 1}, | 
| 90 |  |  |  |  |  |  | {Data   => ['Coit'], | 
| 91 |  |  |  |  |  |  | Weight => 2}]}, | 
| 92 |  |  |  |  |  |  | {Field  => 'Number', | 
| 93 |  |  |  |  |  |  | Values => [{Precondition => "<> eq 'Preston'", | 
| 94 |  |  |  |  |  |  | Alternatives => [{Data => [18100..18199], | 
| 95 |  |  |  |  |  |  | Weight => 1}, | 
| 96 |  |  |  |  |  |  | {Data => [18200..18299], | 
| 97 |  |  |  |  |  |  | Weight => 9}], | 
| 98 |  |  |  |  |  |  | Retry_If     => ['defined $main::addr1 && <> == $main::addr1->{Number}']}, | 
| 99 |  |  |  |  |  |  | {Precondition    => 'DEFAULT', | 
| 100 |  |  |  |  |  |  | Alternatives => [{Data => [18100..18299], | 
| 101 |  |  |  |  |  |  | Weight => 1}]}]} | 
| 102 |  |  |  |  |  |  | ); | 
| 103 |  |  |  |  |  |  |  | 
| 104 |  |  |  |  |  |  | my $randomizer = Randomize->new(\@randomizer_rules); | 
| 105 |  |  |  |  |  |  | while (1) | 
| 106 |  |  |  |  |  |  | $main::addr1 = $main::addr2 = undef; | 
| 107 |  |  |  |  |  |  | $main::addr1 = $randomizer->generate(); | 
| 108 |  |  |  |  |  |  | $main::addr2 = $randomizer->generate(); | 
| 109 |  |  |  |  |  |  | } | 
| 110 |  |  |  |  |  |  |  | 
| 111 |  |  |  |  |  |  | In this example, we're generating pairs of addresses.  The Retry_If clause | 
| 112 |  |  |  |  |  |  | ensures that we never get a pair of identical addresses on Preston.  It's | 
| 113 |  |  |  |  |  |  | still possible to get identical addresses on Coit or Hillcrest, however. | 
| 114 |  |  |  |  |  |  |  | 
| 115 |  |  |  |  |  |  | Retry_If clauses may also appear at the same level as Field and Values, | 
| 116 |  |  |  |  |  |  | like so: | 
| 117 |  |  |  |  |  |  |  | 
| 118 |  |  |  |  |  |  | my @randomizer_rules = | 
| 119 |  |  |  |  |  |  | ( {Field  => 'Street', | 
| 120 |  |  |  |  |  |  | Values => ['Preston', 'Hillcrest', 'Coit']}, | 
| 121 |  |  |  |  |  |  | {Field  => 'Number', | 
| 122 |  |  |  |  |  |  | Values => [18100..18299], | 
| 123 |  |  |  |  |  |  | Retry_If => ['<> eq 'Coit' && <> eq 18200']} | 
| 124 |  |  |  |  |  |  | ); | 
| 125 |  |  |  |  |  |  |  | 
| 126 |  |  |  |  |  |  | This ruleset tells Randomize to try again if the address generated | 
| 127 |  |  |  |  |  |  | is 18200 Coit. | 
| 128 |  |  |  |  |  |  |  | 
| 129 |  |  |  |  |  |  | There is also one special rule that Randomize looks for:  "DEBUG". | 
| 130 |  |  |  |  |  |  | A "DEBUG ON" rule turns debugging messages on so you can see what's | 
| 131 |  |  |  |  |  |  | happening when you call generate().  It also attempts to print the | 
| 132 |  |  |  |  |  |  | code it generates to a file.  You can optionally pass the filename | 
| 133 |  |  |  |  |  |  | in, like "DEBUG ON myfile.code", or if you don't specify a file, | 
| 134 |  |  |  |  |  |  | the default output file is "Randomize.code".  If the file can't | 
| 135 |  |  |  |  |  |  | be opened for writing, a warning is sent to standard error, but | 
| 136 |  |  |  |  |  |  | execution of your program is otherwise unaffected. | 
| 137 |  |  |  |  |  |  |  | 
| 138 |  |  |  |  |  |  | Correspondingly, a "DEBUG OFF" rule turns debugging off, although | 
| 139 |  |  |  |  |  |  | the code is still printed.  Placement of "DEBUG ON" and "DEBUG OFF" | 
| 140 |  |  |  |  |  |  | statements determines which fields debugging information is printed for. | 
| 141 |  |  |  |  |  |  | For example, take a look at the following ruleset: | 
| 142 |  |  |  |  |  |  |  | 
| 143 |  |  |  |  |  |  | my @randomizer_rules = | 
| 144 |  |  |  |  |  |  | ( 'DEBUG ON', | 
| 145 |  |  |  |  |  |  | {Field  => 'Street', | 
| 146 |  |  |  |  |  |  | Values => ['Preston', 'Hillcrest', 'Coit']}, | 
| 147 |  |  |  |  |  |  | 'DEBUG OFF', | 
| 148 |  |  |  |  |  |  | {Field  => 'Number', | 
| 149 |  |  |  |  |  |  | Values => [18100..18299], | 
| 150 |  |  |  |  |  |  | Retry_If => ['<> eq 'Coit' && <> eq 18200']}, | 
| 151 |  |  |  |  |  |  | ); | 
| 152 |  |  |  |  |  |  |  | 
| 153 |  |  |  |  |  |  | This ruleset results in debugging information being printed for | 
| 154 |  |  |  |  |  |  | generation of the "Street" field, but not for the "Number" field, | 
| 155 |  |  |  |  |  |  | and code will be printed to the file "Randomize.code". | 
| 156 |  |  |  |  |  |  |  | 
| 157 |  |  |  |  |  |  | NOTE:  Randomize cannot currently generate anything other than simple | 
| 158 |  |  |  |  |  |  | hashes.  If you want a complex data structure, you'll have to either | 
| 159 |  |  |  |  |  |  | build it yourself by moving items around in the returned hash, or by | 
| 160 |  |  |  |  |  |  | using multiple randomize objects. | 
| 161 |  |  |  |  |  |  |  | 
| 162 |  |  |  |  |  |  | =head2 EXPORT | 
| 163 |  |  |  |  |  |  |  | 
| 164 |  |  |  |  |  |  | None. | 
| 165 |  |  |  |  |  |  |  | 
| 166 |  |  |  |  |  |  | =head1 AUTHOR | 
| 167 |  |  |  |  |  |  |  | 
| 168 |  |  |  |  |  |  | Brand Hilton | 
| 169 |  |  |  |  |  |  |  | 
| 170 |  |  |  |  |  |  | =head1 PUBLIC METHODS | 
| 171 |  |  |  |  |  |  |  | 
| 172 |  |  |  |  |  |  |  | 
| 173 |  |  |  |  |  |  | =cut | 
| 174 |  |  |  |  |  |  |  | 
| 175 |  |  |  |  |  |  |  | 
| 176 |  |  |  |  |  |  | # $Id: Randomize.pm,v 1.10 2001/04/30 13:09:40 bhilton Exp $ | 
| 177 |  |  |  |  |  |  |  | 
| 178 |  |  |  |  |  |  | # $Log: Randomize.pm,v $ | 
| 179 |  |  |  |  |  |  | # Revision 1.10  2001/04/30 13:09:40  bhilton | 
| 180 |  |  |  |  |  |  | # Added generate_all method | 
| 181 |  |  |  |  |  |  | # | 
| 182 |  |  |  |  |  |  | # Revision 1.9  2001/04/24 21:59:35  bhilton | 
| 183 |  |  |  |  |  |  | # Documentation updates | 
| 184 |  |  |  |  |  |  | # | 
| 185 |  |  |  |  |  |  | # Revision 1.8  2001/04/24 14:02:42  bhilton | 
| 186 |  |  |  |  |  |  | # - Added permutations method | 
| 187 |  |  |  |  |  |  | # - Fixed bug that would cause problems if you used both | 
| 188 |  |  |  |  |  |  | #   varieties of Retry_If at the same time | 
| 189 |  |  |  |  |  |  | # | 
| 190 |  |  |  |  |  |  | # Revision 1.7  2001/01/23 15:12:35  bhilton | 
| 191 |  |  |  |  |  |  | # Moving to rev 1.7 for the CPAN bundle. | 
| 192 |  |  |  |  |  |  | # | 
| 193 |  |  |  |  |  |  | # Revision 1.6  2001/01/22 15:13:07  bhilton | 
| 194 |  |  |  |  |  |  | # Added lots of error checking, fixed a couple of minor bugs. | 
| 195 |  |  |  |  |  |  | # | 
| 196 |  |  |  |  |  |  | # Revision 1.5  2000/12/01 19:41:08  bhilton | 
| 197 |  |  |  |  |  |  | # Changed first-level "Alternatives" to "Values". | 
| 198 |  |  |  |  |  |  | # Added DEBUG flag. | 
| 199 |  |  |  |  |  |  | # | 
| 200 |  |  |  |  |  |  | # Revision 1.4  2000/11/21 20:40:16  bhilton | 
| 201 |  |  |  |  |  |  | # Added "Retry_If" capabilities. | 
| 202 |  |  |  |  |  |  | # | 
| 203 |  |  |  |  |  |  | # Revision 1.3  2000/11/18 23:50:59  bhilton | 
| 204 |  |  |  |  |  |  | # Various improvements and bug fixes. | 
| 205 |  |  |  |  |  |  | # | 
| 206 |  |  |  |  |  |  | # Revision 1.2  2000/11/18 22:56:38  bhilton | 
| 207 |  |  |  |  |  |  | # When you call generate, you can now specify the value of one or more | 
| 208 |  |  |  |  |  |  | # fields in the hash. | 
| 209 |  |  |  |  |  |  | # | 
| 210 |  |  |  |  |  |  | # Revision 1.1  2000/11/18 22:07:59  bhilton | 
| 211 |  |  |  |  |  |  | # Initial revision | 
| 212 |  |  |  |  |  |  | # | 
| 213 |  |  |  |  |  |  |  | 
| 214 |  |  |  |  |  |  | require 5.005_62; | 
| 215 | 1 |  |  | 1 |  | 20988 | use strict; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 43 |  | 
| 216 | 1 |  |  | 1 |  | 5 | use warnings; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 31 |  | 
| 217 | 1 |  |  | 1 |  | 5 | use Data::Dumper; | 
|  | 1 |  |  |  |  | 7 |  | 
|  | 1 |  |  |  |  | 5576 |  | 
| 218 |  |  |  |  |  |  | $Data::Dumper::Deepcopy = 1; | 
| 219 |  |  |  |  |  |  |  | 
| 220 |  |  |  |  |  |  | our ($VERSION) = '$Revision: 1.10 $'=~/(\d+(\.\d+))/; | 
| 221 |  |  |  |  |  |  |  | 
| 222 |  |  |  |  |  |  | our $errmsg = ''; | 
| 223 |  |  |  |  |  |  |  | 
| 224 |  |  |  |  |  |  |  | 
| 225 |  |  |  |  |  |  | sub _process_alternatives { | 
| 226 | 23 |  |  | 23 |  | 44 | my ($fieldname, $valueno, $alts) = @_; | 
| 227 | 23 |  |  |  |  | 32 | my @array; | 
| 228 |  |  |  |  |  |  |  | 
| 229 | 23 |  |  |  |  | 85 | foreach my $index (0..$#{$alts}) { | 
|  | 23 |  |  |  |  | 64 |  | 
| 230 | 42 |  |  |  |  | 178 | my $ary = $alts->[$index]; | 
| 231 |  |  |  |  |  |  |  | 
| 232 | 42 | 100 |  |  |  | 174 | unless (exists $ary->{Data}) { | 
| 233 | 3 |  |  |  |  | 16 | $errmsg = "Field $fieldname Value $valueno Alternative $index " | 
| 234 |  |  |  |  |  |  | . "doesn't contain a Data element"; | 
| 235 | 3 |  |  |  |  | 28 | return; | 
| 236 |  |  |  |  |  |  | } | 
| 237 |  |  |  |  |  |  |  | 
| 238 | 39 | 100 |  |  |  | 311 | unless (exists $ary->{Weight}) { | 
| 239 | 2 |  |  |  |  | 9 | $errmsg = "Field $fieldname Value $valueno Alternative $index " | 
| 240 |  |  |  |  |  |  | . "doesn't contain a Weight element"; | 
| 241 | 2 |  |  |  |  | 15 | return; | 
| 242 |  |  |  |  |  |  | } | 
| 243 |  |  |  |  |  |  |  | 
| 244 | 37 | 100 |  |  |  | 226 | unless (ref $ary->{Data} eq 'ARRAY') { | 
| 245 | 2 |  |  |  |  | 10 | $errmsg = "Field $fieldname Value $valueno Alternative $index: " | 
| 246 |  |  |  |  |  |  | . "Data element isn't an array ref."; | 
| 247 | 2 |  |  |  |  | 16 | return; | 
| 248 |  |  |  |  |  |  | } | 
| 249 |  |  |  |  |  |  |  | 
| 250 | 35 | 100 |  |  |  | 209 | unless ($ary->{Weight} =~ /^\d+$/) { | 
| 251 | 2 |  |  |  |  | 11 | $errmsg = "Field $fieldname Value $valueno Alternative $index: " | 
| 252 |  |  |  |  |  |  | . "Weight element isn't a positive integer."; | 
| 253 | 2 |  |  |  |  | 17 | return; | 
| 254 |  |  |  |  |  |  | } | 
| 255 |  |  |  |  |  |  |  | 
| 256 | 33 |  |  |  |  | 136 | push @array, (@{$ary->{Data}}) x $ary->{Weight}; | 
|  | 33 |  |  |  |  | 282 |  | 
| 257 |  |  |  |  |  |  | } | 
| 258 | 14 |  |  |  |  | 110 | return Data::Dumper->Dump([\@array], ['$stuff']); | 
| 259 |  |  |  |  |  |  | } | 
| 260 |  |  |  |  |  |  |  | 
| 261 |  |  |  |  |  |  |  | 
| 262 |  |  |  |  |  |  | # _create_generate_method | 
| 263 |  |  |  |  |  |  | # | 
| 264 |  |  |  |  |  |  | # This subroutine creates the Generate method of the randomizer. | 
| 265 |  |  |  |  |  |  | # It takes the same set of rules that the new() method takes, and | 
| 266 |  |  |  |  |  |  | # returns a code reference. | 
| 267 |  |  |  |  |  |  |  | 
| 268 |  |  |  |  |  |  | sub _create_generate_method { | 
| 269 | 30 |  |  | 30 |  | 80 | my ($rules) = @_; | 
| 270 |  |  |  |  |  |  |  | 
| 271 | 30 |  |  |  |  | 33 | my $print_filename;   # Name of the file to print code to.  Also serves | 
| 272 |  |  |  |  |  |  | # as a flag signalling whether to print code at all. | 
| 273 |  |  |  |  |  |  |  | 
| 274 | 30 |  |  |  |  | 63 | my $code = "sub {\n" | 
| 275 |  |  |  |  |  |  | . "  my \%retval = \@_;\n" | 
| 276 |  |  |  |  |  |  | . "  my \$stuff;\n" | 
| 277 |  |  |  |  |  |  | . "  my \$debug = 0;\n" | 
| 278 |  |  |  |  |  |  | . "  my \$counter;\n\n"; | 
| 279 |  |  |  |  |  |  |  | 
| 280 | 30 |  |  |  |  | 45 | foreach my $i (0..$#{$rules}) { | 
|  | 30 |  |  |  |  | 98 |  | 
| 281 | 45 | 100 |  |  |  | 240 | if ($rules->[$i] =~ /^\s*DEBUG\s/i) { | 
| 282 | 5 | 100 |  |  |  | 241 | unless ($rules->[$i] =~ /^\s*DEBUG\s+(ON|OFF)\s*(.*?)\s*$/i) { | 
| 283 | 1 |  |  |  |  | 53 | $errmsg = "Syntax error in DEBUG directive"; | 
| 284 | 1 |  |  |  |  | 10 | return; | 
| 285 |  |  |  |  |  |  | } | 
| 286 | 4 |  |  |  |  | 12 | my $onoff = uc $1; | 
| 287 | 4 | 100 | 100 |  |  | 84 | $print_filename = $2 || 'Randomize.code' if $onoff eq 'ON'; | 
| 288 | 4 |  |  |  |  | 18 | $code .= "  \$debug = " . {ON => 1, OFF => 0}->{$onoff} . ";\n\n"; | 
| 289 | 4 |  |  |  |  | 12 | next; | 
| 290 |  |  |  |  |  |  | } | 
| 291 |  |  |  |  |  |  |  | 
| 292 | 40 | 100 |  |  |  | 121 | unless (exists $rules->[$i]{Field}) { | 
| 293 | 1 |  |  |  |  | 5 | $errmsg = "Rule " . ($i+1) . " doesn't contain a field name"; | 
| 294 | 1 |  |  |  |  | 8 | return; | 
| 295 |  |  |  |  |  |  | } | 
| 296 |  |  |  |  |  |  |  | 
| 297 | 39 | 100 |  |  |  | 109 | unless (exists $rules->[$i]{Values}) { | 
| 298 | 1 |  |  |  |  | 4 | $errmsg = "Field '$rules->[$i]{Field}' doesn't have a Values field"; | 
| 299 | 1 |  |  |  |  | 7 | return; | 
| 300 |  |  |  |  |  |  | } | 
| 301 |  |  |  |  |  |  |  | 
| 302 |  |  |  |  |  |  |  | 
| 303 | 38 |  |  |  |  | 62 | my $fieldname = $rules->[$i]{Field}; | 
| 304 |  |  |  |  |  |  |  | 
| 305 | 38 | 50 |  |  |  | 115 | if (ref $rules->[$i]{Values} eq 'ARRAY') { | 
| 306 | 38 |  |  |  |  | 52 | my $outer_retry_clause; | 
| 307 | 38 |  |  |  |  | 48 | my $outer_indent = '  '; | 
| 308 | 38 | 100 |  |  |  | 101 | if (exists $rules->[$i]{Retry_If}) { | 
| 309 | 7 |  |  |  |  | 29 | $outer_retry_clause = '(' | 
| 310 | 7 |  |  |  |  | 15 | . join(') || (', @{$rules->[$i]{Retry_If}}) | 
| 311 |  |  |  |  |  |  | . ')'; | 
| 312 | 7 |  |  |  |  | 92 | $outer_retry_clause =~ s/<<(.*?)>>/\$retval{$1}/g; | 
| 313 |  |  |  |  |  |  | } | 
| 314 | 38 | 100 |  |  |  | 186 | if (ref $rules->[$i]{Values}[0] eq '') { | 
|  |  | 50 |  |  |  |  |  | 
| 315 |  |  |  |  |  |  | # In the form [1..15] or ['one', 'two', 'three'] | 
| 316 | 13 | 100 |  |  |  | 50 | if (exists $rules->[$i]{Retry_If}) { | 
| 317 | 1 |  |  |  |  | 4 | $code .= _retry_if_start_for_generate($outer_retry_clause, | 
| 318 |  |  |  |  |  |  | $fieldname, | 
| 319 |  |  |  |  |  |  | $outer_indent); | 
| 320 | 1 |  |  |  |  | 2 | $outer_indent .= '      '; | 
| 321 |  |  |  |  |  |  | } | 
| 322 | 13 |  |  |  |  | 151 | my $temp_code = Data::Dumper->Dump([$rules->[$i]{Values}], ['$stuff']); | 
| 323 | 13 |  |  |  |  | 1176 | $temp_code =~ s/^/  /mg; | 
| 324 | 13 |  |  |  |  | 27 | $code .= $temp_code; | 
| 325 | 13 | 100 |  |  |  | 96 | if (exists $rules->[$i]{Retry_If}) { | 
| 326 | 1 |  |  |  |  | 5 | $code .= _retry_if_finish_for_generate($outer_retry_clause, | 
| 327 |  |  |  |  |  |  | $fieldname, | 
| 328 |  |  |  |  |  |  | $outer_indent); | 
| 329 |  |  |  |  |  |  | } | 
| 330 |  |  |  |  |  |  | else { | 
| 331 | 12 |  |  |  |  | 39 | $code .= "  \$retval{$fieldname} ||= \$stuff->[rand \@\$stuff];\n"; | 
| 332 | 12 |  |  |  |  | 49 | $code .= "  print \"$fieldname just set to \$retval{$fieldname}\\n\" if \$debug;\n\n"; | 
| 333 |  |  |  |  |  |  | } | 
| 334 |  |  |  |  |  |  | } | 
| 335 |  |  |  |  |  |  | elsif (ref $rules->[$i]{Values}[0] eq 'HASH') { | 
| 336 | 25 | 100 |  |  |  | 86 | if (exists $rules->[$i]{Values}[0]{Alternatives}) { | 
| 337 |  |  |  |  |  |  | # In the form [{Precondition => "<> eq 'Preston'", | 
| 338 |  |  |  |  |  |  | #               Alternatives => [{Data => [18100..18199], | 
| 339 |  |  |  |  |  |  | #                                 Weight => 1}, | 
| 340 |  |  |  |  |  |  | #                                {Data => [18200..18299], | 
| 341 |  |  |  |  |  |  | #                                 Weight => 9}], | 
| 342 |  |  |  |  |  |  | #               Retry_If     => "<> == 18113"}, | 
| 343 |  |  |  |  |  |  | #              {Precondition => 'DEFAULT', | 
| 344 |  |  |  |  |  |  | #               Alternatives => [{Data => [18100..18299], | 
| 345 |  |  |  |  |  |  | #                                 Weight => 1}]}] | 
| 346 | 18 |  |  |  |  | 32 | my $done = 0; | 
| 347 | 18 |  |  |  |  | 24 | my $branchno = 1; | 
| 348 | 18 |  |  |  |  | 29 | $code .= "  \$counter = 0;\n"; | 
| 349 | 18 |  |  |  |  | 26 | foreach my $j (0..$#{$rules->[$i]{Values}}) { | 
|  | 18 |  |  |  |  | 55 |  | 
| 350 | 38 |  |  |  |  | 279 | my $hash = $rules->[$i]{Values}[$j]; | 
| 351 |  |  |  |  |  |  |  | 
| 352 | 38 | 100 |  |  |  | 114 | unless (exists $hash->{Precondition}) { | 
| 353 | 1 |  |  |  |  | 7 | $errmsg = "Field '$fieldname', Value " . ($j+1) . | 
| 354 |  |  |  |  |  |  | ": No precondition given."; | 
| 355 | 1 |  |  |  |  | 8 | return; | 
| 356 |  |  |  |  |  |  | } | 
| 357 |  |  |  |  |  |  |  | 
| 358 | 37 | 50 |  |  |  | 128 | unless (exists $hash->{Alternatives}) { | 
| 359 | 0 |  |  |  |  | 0 | $errmsg = "Field '$fieldname', Value " . ($j+1) . | 
| 360 |  |  |  |  |  |  | ": No alternatives given."; | 
| 361 | 0 |  |  |  |  | 0 | return; | 
| 362 |  |  |  |  |  |  | } | 
| 363 |  |  |  |  |  |  |  | 
| 364 | 37 |  |  |  |  | 134 | my $condition = $hash->{Precondition}; | 
| 365 | 37 | 100 |  |  |  | 107 | if ($condition eq 'DEFAULT') { | 
| 366 | 17 | 100 |  |  |  | 41 | if ($branchno > 1) { | 
| 367 | 10 |  |  |  |  | 21 | $code .= "  else {\n"; | 
| 368 | 10 |  |  |  |  | 65 | $code .= "    print \"Field $fieldname, inside else\\n\" if \$debug;\n"; | 
| 369 |  |  |  |  |  |  | } | 
| 370 |  |  |  |  |  |  | else { | 
| 371 | 7 |  |  |  |  | 11 | $code .= "  if (1) {\n"; | 
| 372 | 7 |  |  |  |  | 14 | $code .= "    print \"Field $fieldname, inside if (1)\\n\" if \$debug;\n"; | 
| 373 |  |  |  |  |  |  | } | 
| 374 | 17 |  |  |  |  | 47 | $done = 1; | 
| 375 |  |  |  |  |  |  | } | 
| 376 |  |  |  |  |  |  | else { | 
| 377 | 20 | 50 |  |  |  | 123 | if ($done) { | 
| 378 | 0 |  |  |  |  | 0 | $errmsg = "Error in field '$fieldname':  " . | 
| 379 |  |  |  |  |  |  | "DEFAULT must be the last condition listed."; | 
| 380 | 0 |  |  |  |  | 0 | return; | 
| 381 |  |  |  |  |  |  | } | 
| 382 | 20 |  |  |  |  | 198 | $condition =~ s/<<(.*?)>>/\$retval{$1}/g; | 
| 383 | 20 |  |  |  |  | 39 | $code .= '  '; | 
| 384 | 20 | 100 |  |  |  | 207 | $code .= 'els' if $branchno > 1; | 
| 385 | 20 |  |  |  |  | 45 | $code .= "if ($condition) {\n"; | 
| 386 | 20 |  |  |  |  | 46 | $code .= "    print \"Field $fieldname, inside branch number $branchno\\n\" if \$debug;\n"; | 
| 387 | 20 |  |  |  |  | 33 | $branchno++; | 
| 388 |  |  |  |  |  |  | } | 
| 389 |  |  |  |  |  |  |  | 
| 390 | 37 |  |  |  |  | 42 | my $retry_clause; | 
| 391 | 37 |  |  |  |  | 51 | my $indent = '    '; | 
| 392 | 37 | 100 |  |  |  | 97 | if (exists $hash->{Retry_If}) { | 
| 393 | 12 |  |  |  |  | 44 | $retry_clause = '(' | 
| 394 | 12 |  |  |  |  | 23 | . join(') || (', @{$hash->{Retry_If}}) | 
| 395 |  |  |  |  |  |  | . ')'; | 
| 396 | 12 |  |  |  |  | 109 | $retry_clause =~ s/<<(.*?)>>/\$retval{$1}/g; | 
| 397 |  |  |  |  |  |  | } | 
| 398 |  |  |  |  |  |  |  | 
| 399 | 37 | 100 | 100 |  |  | 283 | if (exists $hash->{Retry_If} || exists $rules->[$i]{Retry_If}) { | 
| 400 | 24 |  |  |  |  | 35 | my @clauses; | 
| 401 | 24 | 100 |  |  |  | 80 | push @clauses, $retry_clause if exists $hash->{Retry_If}; | 
| 402 | 24 | 100 |  |  |  | 81 | push @clauses, $outer_retry_clause | 
| 403 |  |  |  |  |  |  | if exists $rules->[$i]{Retry_If}; | 
| 404 | 24 |  |  |  |  | 68 | $retry_clause = '(' . join(' || ', @clauses) . ')'; | 
| 405 | 24 |  |  |  |  | 63 | $code .= _retry_if_start_for_generate($retry_clause, | 
| 406 |  |  |  |  |  |  | $fieldname, | 
| 407 |  |  |  |  |  |  | $indent); | 
| 408 | 24 |  |  |  |  | 55 | $indent .= '    '; | 
| 409 |  |  |  |  |  |  | } | 
| 410 |  |  |  |  |  |  |  | 
| 411 | 37 |  |  |  |  | 44 | my $temp_code; | 
| 412 | 37 | 100 |  |  |  | 148 | if (ref $hash->{Alternatives}[0] eq '') { | 
|  |  | 50 |  |  |  |  |  | 
| 413 |  |  |  |  |  |  | # In the form [1..15] or ['one', 'two', 'three'] | 
| 414 | 21 |  |  |  |  | 179 | $temp_code = Data::Dumper->Dump([$hash->{Alternatives}], ['$stuff']); | 
| 415 |  |  |  |  |  |  | } | 
| 416 |  |  |  |  |  |  | elsif (ref $hash->{Alternatives}[0] eq 'HASH') { | 
| 417 | 16 | 100 |  |  |  | 617 | $temp_code = _process_alternatives($fieldname, $j, | 
| 418 |  |  |  |  |  |  | $hash->{Alternatives}) | 
| 419 |  |  |  |  |  |  | or return; | 
| 420 |  |  |  |  |  |  | } | 
| 421 |  |  |  |  |  |  | else { | 
| 422 | 0 |  |  |  |  | 0 | $errmsg = "Error in Field '$fieldname'.  " . | 
| 423 |  |  |  |  |  |  | "First element of the conditional Alternatives " . | 
| 424 |  |  |  |  |  |  | "array is neither a scalar nor an array."; | 
| 425 | 0 |  |  |  |  | 0 | return; | 
| 426 |  |  |  |  |  |  | } | 
| 427 | 33 |  |  |  |  | 3809 | $temp_code =~ s/^/$indent/mg; | 
| 428 | 33 |  |  |  |  | 73 | $code .= $temp_code; | 
| 429 |  |  |  |  |  |  |  | 
| 430 | 33 | 100 | 100 |  |  | 505 | if (exists $hash->{Retry_If} || exists $rules->[$i]{Retry_If}) { | 
| 431 | 20 |  |  |  |  | 61 | $code .= _retry_if_finish_for_generate($retry_clause, | 
| 432 |  |  |  |  |  |  | $fieldname, | 
| 433 |  |  |  |  |  |  | $indent); | 
| 434 |  |  |  |  |  |  | } | 
| 435 |  |  |  |  |  |  | else { | 
| 436 | 13 |  |  |  |  | 38 | $code .= $indent . "\$retval{$fieldname} ||= \$stuff->[rand \@\$stuff];\n\n"; | 
| 437 | 13 |  |  |  |  | 36 | $code .= $indent . "print \"$fieldname just set to \$retval{$fieldname}\\n\" if \$debug;\n\n"; | 
| 438 |  |  |  |  |  |  | } | 
| 439 | 33 |  |  |  |  | 134 | $code .= "  }\n\n"; | 
| 440 |  |  |  |  |  |  | } | 
| 441 |  |  |  |  |  |  | #if (exists $rules->[$i]{Retry_If}) { | 
| 442 |  |  |  |  |  |  | #  $code .= substr($outer_indent, 0, length($outer_indent)-2) . "}\n"; | 
| 443 |  |  |  |  |  |  | #  $code .= substr($outer_indent, 0, length($outer_indent)-4) . "}\n"; | 
| 444 |  |  |  |  |  |  | #} | 
| 445 |  |  |  |  |  |  | } | 
| 446 |  |  |  |  |  |  | else { | 
| 447 |  |  |  |  |  |  | # In the form [{Data   => [1..5], | 
| 448 |  |  |  |  |  |  | #               Weight => 1}, | 
| 449 |  |  |  |  |  |  | #              {Data   => [6..10], | 
| 450 |  |  |  |  |  |  | #               Weight => 2}] | 
| 451 | 7 | 100 |  |  |  | 27 | if (exists $rules->[$i]{Retry_If}) { | 
| 452 | 1 |  |  |  |  | 3 | $code .= _retry_if_start_for_generate($outer_retry_clause, | 
| 453 |  |  |  |  |  |  | $fieldname, | 
| 454 |  |  |  |  |  |  | $outer_indent); | 
| 455 | 1 |  |  |  |  | 2 | $outer_indent .= '      '; | 
| 456 |  |  |  |  |  |  | } | 
| 457 | 7 |  | 100 |  |  | 26 | my $temp_code .= (_process_alternatives($fieldname, 0, | 
| 458 |  |  |  |  |  |  | $rules->[$i]{Values}) | 
| 459 |  |  |  |  |  |  | or return); | 
| 460 | 2 |  |  |  |  | 343 | $temp_code =~ s/^/$outer_indent/mg; | 
| 461 | 2 |  |  |  |  | 6 | $code .= $temp_code; | 
| 462 | 2 | 100 |  |  |  | 9 | if (exists $rules->[$i]{Retry_If}) { | 
| 463 | 1 |  |  |  |  | 7 | $code .= _retry_if_finish_for_generate($outer_retry_clause, | 
| 464 |  |  |  |  |  |  | $fieldname, | 
| 465 |  |  |  |  |  |  | $outer_indent); | 
| 466 |  |  |  |  |  |  | } | 
| 467 |  |  |  |  |  |  | else { | 
| 468 | 1 |  |  |  |  | 4 | $code .= "  \$retval{$fieldname} ||= \$stuff->[rand \@\$stuff];\n\n"; | 
| 469 | 1 |  |  |  |  | 7 | $code .= "  print \"$fieldname just set to \$retval{$fieldname}\\n\" if \$debug;\n\n"; | 
| 470 |  |  |  |  |  |  | } | 
| 471 |  |  |  |  |  |  | } | 
| 472 |  |  |  |  |  |  | } | 
| 473 |  |  |  |  |  |  | else { | 
| 474 | 0 |  |  |  |  | 0 | $errmsg = "Error in field '$fieldname':  " . | 
| 475 |  |  |  |  |  |  | "First element of Values is neither a scalar nor a hash."; | 
| 476 | 0 |  |  |  |  | 0 | return; | 
| 477 |  |  |  |  |  |  | } | 
| 478 |  |  |  |  |  |  | } | 
| 479 |  |  |  |  |  |  | else { | 
| 480 | 0 |  |  |  |  | 0 | $errmsg = "Error in field '$fieldname':  " . | 
| 481 |  |  |  |  |  |  | "Values element should be an array."; | 
| 482 | 0 |  |  |  |  | 0 | return; | 
| 483 |  |  |  |  |  |  | } | 
| 484 |  |  |  |  |  |  | } | 
| 485 |  |  |  |  |  |  |  | 
| 486 | 17 |  |  |  |  | 43 | $code .= "  return \\\%retval;\n}\n"; | 
| 487 |  |  |  |  |  |  |  | 
| 488 | 17 | 100 |  |  |  | 42 | if ($print_filename) { | 
| 489 | 2 | 50 |  |  |  | 40363 | if (open CODE, ">$print_filename") { | 
| 490 | 2 |  |  |  |  | 30 | print CODE "# generate() method\n\n", $code; | 
| 491 | 2 |  |  |  |  | 206 | close CODE; | 
| 492 |  |  |  |  |  |  | } | 
| 493 |  |  |  |  |  |  | else { | 
| 494 | 0 |  |  |  |  | 0 | print STDERR "Failed to open $print_filename for writing: $!"; | 
| 495 |  |  |  |  |  |  | } | 
| 496 |  |  |  |  |  |  | } | 
| 497 |  |  |  |  |  |  |  | 
| 498 | 17 |  |  |  |  | 13502 | my $retval = eval $code; | 
| 499 | 17 | 50 |  |  |  | 80 | unless (defined $retval) { | 
| 500 | 0 |  |  |  |  | 0 | $errmsg = $@; | 
| 501 | 0 |  |  |  |  | 0 | return; | 
| 502 |  |  |  |  |  |  | } | 
| 503 | 17 |  |  |  |  | 112 | return $retval; | 
| 504 |  |  |  |  |  |  | } | 
| 505 |  |  |  |  |  |  |  | 
| 506 |  |  |  |  |  |  |  | 
| 507 |  |  |  |  |  |  | # _create_permutations_generateall_method | 
| 508 |  |  |  |  |  |  | # | 
| 509 |  |  |  |  |  |  | # This subroutine creates the anonymous sub that implements both | 
| 510 |  |  |  |  |  |  | # the permutations() and the generate_all() methods of the randomizer. | 
| 511 |  |  |  |  |  |  | # It takes the same set of rules that the new() method takes, and | 
| 512 |  |  |  |  |  |  | # returns a code reference. | 
| 513 |  |  |  |  |  |  |  | 
| 514 |  |  |  |  |  |  | sub _create_permutations_generateall_method { | 
| 515 | 17 |  |  | 17 |  | 66 | my ($rules) = @_; | 
| 516 |  |  |  |  |  |  |  | 
| 517 | 17 |  |  |  |  | 23 | my $print_filename;   # Name of the file to print code to.  Also serves | 
| 518 |  |  |  |  |  |  | # as a flag signalling whether to print code at all. | 
| 519 | 17 |  |  |  |  | 30 | my $nestlevel = 0; | 
| 520 |  |  |  |  |  |  |  | 
| 521 | 17 |  |  |  |  | 25 | my @fieldnames; | 
| 522 |  |  |  |  |  |  |  | 
| 523 | 17 |  |  |  |  | 31 | my $retry_code = ''; | 
| 524 |  |  |  |  |  |  |  | 
| 525 | 17 |  |  |  |  | 35 | my $code = "sub {\n" | 
| 526 |  |  |  |  |  |  | . "  my \$count_or_generate = shift;\n" | 
| 527 |  |  |  |  |  |  | . "  my \%parms  = \@_;\n" | 
| 528 |  |  |  |  |  |  | . "  my \%retval = \@_;\n" | 
| 529 |  |  |  |  |  |  | . "  my \$stuff;\n" | 
| 530 |  |  |  |  |  |  | . "  my \$debug = 0;\n" | 
| 531 |  |  |  |  |  |  | . "  my \@retlist;\n" | 
| 532 |  |  |  |  |  |  | . "  my \$permutations = 0;\n\n"; | 
| 533 |  |  |  |  |  |  |  | 
| 534 | 17 |  |  |  |  | 27 | foreach my $i (0..$#{$rules}) { | 
|  | 17 |  |  |  |  | 63 |  | 
| 535 | 32 | 100 |  |  |  | 178 | if ($rules->[$i] =~ /^\s*DEBUG\s/i) { | 
| 536 | 4 | 50 |  |  |  | 37 | unless ($rules->[$i] =~ /^\s*DEBUG\s+(ON|OFF)\s*(.*?)\s*$/i) { | 
| 537 | 0 |  |  |  |  | 0 | $errmsg = "Syntax error in DEBUG directive"; | 
| 538 | 0 |  |  |  |  | 0 | return; | 
| 539 |  |  |  |  |  |  | } | 
| 540 | 4 |  |  |  |  | 10 | my $onoff = uc $1; | 
| 541 | 4 | 100 | 100 |  |  | 29 | $print_filename = $2 || 'Randomize.code' if $onoff eq 'ON'; | 
| 542 | 4 |  |  |  |  | 20 | $code .= "  \$debug = " . {ON => 1, OFF => 0}->{$onoff} . ";\n\n"; | 
| 543 | 4 |  |  |  |  | 15 | next; | 
| 544 |  |  |  |  |  |  | } | 
| 545 |  |  |  |  |  |  |  | 
| 546 | 28 | 50 |  |  |  | 85 | unless (exists $rules->[$i]{Field}) { | 
| 547 | 0 |  |  |  |  | 0 | $errmsg = "Rule " . ($i+1) . " doesn't contain a field name"; | 
| 548 | 0 |  |  |  |  | 0 | return; | 
| 549 |  |  |  |  |  |  | } | 
| 550 |  |  |  |  |  |  |  | 
| 551 | 28 | 50 |  |  |  | 74 | unless (exists $rules->[$i]{Values}) { | 
| 552 | 0 |  |  |  |  | 0 | $errmsg = "Field '$rules->[$i]{Field}' doesn't have a Values field"; | 
| 553 | 0 |  |  |  |  | 0 | return; | 
| 554 |  |  |  |  |  |  | } | 
| 555 |  |  |  |  |  |  |  | 
| 556 |  |  |  |  |  |  |  | 
| 557 | 28 |  |  |  |  | 56 | my $fieldname = $rules->[$i]{Field}; | 
| 558 |  |  |  |  |  |  |  | 
| 559 | 28 | 50 |  |  |  | 95 | if (ref $rules->[$i]{Values} eq 'ARRAY') { | 
| 560 | 28 |  |  |  |  | 34 | my $outer_retry_clause; | 
| 561 | 28 |  |  |  |  | 46 | my $outer_indent = '  '; | 
| 562 | 28 | 100 |  |  |  | 91 | if (exists $rules->[$i]{Retry_If}) { | 
| 563 | 7 |  |  |  |  | 36 | $outer_retry_clause = '(' | 
| 564 | 7 |  |  |  |  | 14 | . join(') || (', @{$rules->[$i]{Retry_If}}) | 
| 565 |  |  |  |  |  |  | . ')'; | 
| 566 | 7 |  |  |  |  | 150 | $outer_retry_clause =~ s/<<(.*?)>>/\$retval{$1}/g; | 
| 567 | 7 |  |  |  |  | 20 | $retry_code .= "    if ($outer_retry_clause) {\n"; | 
| 568 | 7 |  |  |  |  | 14 | $retry_code .= "      print \"  rejected\\n\" if \$debug;\n"; | 
| 569 | 7 |  |  |  |  | 10 | $retry_code .= "      next;\n"; | 
| 570 | 7 |  |  |  |  | 16 | $retry_code .= "    }\n"; | 
| 571 |  |  |  |  |  |  | #$code .= _retry_if_start_for_permutations($outer_retry_clause, | 
| 572 |  |  |  |  |  |  | #                                          $fieldname, | 
| 573 |  |  |  |  |  |  | #                                          $outer_indent); | 
| 574 | 7 |  |  |  |  | 13 | $outer_indent .= '      '; | 
| 575 |  |  |  |  |  |  | } | 
| 576 | 28 | 100 |  |  |  | 148 | if (ref $rules->[$i]{Values}[0] eq '') { | 
|  |  | 50 |  |  |  |  |  | 
| 577 |  |  |  |  |  |  | # In the form [1..15] or ['one', 'two', 'three'] | 
| 578 | 13 |  |  |  |  | 92 | my $temp_code = Data::Dumper->Dump([$rules->[$i]{Values}], ['$stuff']); | 
| 579 | 13 |  |  |  |  | 1461 | $temp_code =~ s/^/    /mg; | 
| 580 | 13 |  |  |  |  | 39 | $code .= "  if (\$parms{$fieldname}) {\n"; | 
| 581 | 13 |  |  |  |  | 34 | $code .= "    \$stuff = [\"\$parms{$fieldname}\"];\n"; | 
| 582 | 13 |  |  |  |  | 36 | $code .= "  }\n"; | 
| 583 | 13 |  |  |  |  | 24 | $code .= "  else {\n"; | 
| 584 | 13 |  |  |  |  | 24 | $code .= $temp_code; | 
| 585 | 13 |  |  |  |  | 20 | $code .= "  }\n"; | 
| 586 | 13 |  |  |  |  | 71 | $code .= "  foreach my \$thingy (\@\$stuff) {\n"; | 
| 587 | 13 |  |  |  |  | 27 | $code .= "    \$retval{$fieldname} = \$thingy;\n"; | 
| 588 | 13 |  |  |  |  | 30 | $code .= "    print \"$fieldname just set to \$retval{$fieldname}\\n\" if \$debug;\n\n"; | 
| 589 | 13 |  |  |  |  | 26 | $fieldnames[$nestlevel] = $fieldname; | 
| 590 | 13 |  |  |  |  | 39 | $nestlevel++; | 
| 591 |  |  |  |  |  |  | } | 
| 592 |  |  |  |  |  |  | elsif (ref $rules->[$i]{Values}[0] eq 'HASH') { | 
| 593 | 15 | 100 |  |  |  | 142 | if (exists $rules->[$i]{Values}[0]{Alternatives}) { | 
| 594 |  |  |  |  |  |  | # In the form [{Precondition => "<> eq 'Preston'", | 
| 595 |  |  |  |  |  |  | #               Alternatives => [{Data => [18100..18199], | 
| 596 |  |  |  |  |  |  | #                                 Weight => 1}, | 
| 597 |  |  |  |  |  |  | #                                {Data => [18200..18299], | 
| 598 |  |  |  |  |  |  | #                                 Weight => 9}], | 
| 599 |  |  |  |  |  |  | #               Retry_If     => "<> == 18113"}, | 
| 600 |  |  |  |  |  |  | #              {Precondition => 'DEFAULT', | 
| 601 |  |  |  |  |  |  | #               Alternatives => [{Data => [18100..18299], | 
| 602 |  |  |  |  |  |  | #                                 Weight => 1}]}] | 
| 603 | 13 |  |  |  |  | 31 | my $done = 0; | 
| 604 | 13 |  |  |  |  | 21 | my $branchno = 1; | 
| 605 | 13 |  |  |  |  | 33 | $code .= "  if (\$parms{$fieldname}) {\n"; | 
| 606 |  |  |  |  |  |  | #$code .= "    \$stuff = [\"\$parms{$fieldname}\"];\n"; | 
| 607 | 13 |  |  |  |  | 25 | $code .= "    \$stuff = [\$parms{$fieldname}];\n"; | 
| 608 | 13 |  |  |  |  | 23 | $code .= "  }\n"; | 
| 609 | 13 |  |  |  |  | 28 | foreach my $j (0..$#{$rules->[$i]{Values}}) { | 
|  | 13 |  |  |  |  | 41 |  | 
| 610 | 33 |  |  |  |  | 85 | my $hash = $rules->[$i]{Values}[$j]; | 
| 611 |  |  |  |  |  |  |  | 
| 612 | 33 | 50 |  |  |  | 92 | unless (exists $hash->{Precondition}) { | 
| 613 | 0 |  |  |  |  | 0 | $errmsg = "Field '$fieldname', Value " . ($j+1) . | 
| 614 |  |  |  |  |  |  | ": No precondition given."; | 
| 615 | 0 |  |  |  |  | 0 | return; | 
| 616 |  |  |  |  |  |  | } | 
| 617 |  |  |  |  |  |  |  | 
| 618 | 33 | 50 |  |  |  | 93 | unless (exists $hash->{Alternatives}) { | 
| 619 | 0 |  |  |  |  | 0 | $errmsg = "Field '$fieldname', Value " . ($j+1) . | 
| 620 |  |  |  |  |  |  | ": No alternatives given."; | 
| 621 | 0 |  |  |  |  | 0 | return; | 
| 622 |  |  |  |  |  |  | } | 
| 623 |  |  |  |  |  |  |  | 
| 624 | 33 |  |  |  |  | 96 | my $condition = $hash->{Precondition}; | 
| 625 | 33 | 100 |  |  |  | 75 | if ($condition eq 'DEFAULT') { | 
| 626 | 13 | 100 |  |  |  | 40 | if ($branchno > 1) { | 
| 627 | 10 |  |  |  |  | 17 | $code .= "  else {\n"; | 
| 628 | 10 |  |  |  |  | 21 | $code .= "    print \"Field $fieldname, inside else\\n\" if \$debug;\n"; | 
| 629 |  |  |  |  |  |  | } | 
| 630 |  |  |  |  |  |  | else { | 
| 631 | 3 |  |  |  |  | 6 | $code .= "  if (1) {\n"; | 
| 632 | 3 |  |  |  |  | 10 | $code .= "    print \"Field $fieldname, inside if (1)\\n\" if \$debug;\n"; | 
| 633 |  |  |  |  |  |  | } | 
| 634 | 13 |  |  |  |  | 17 | $done = 1; | 
| 635 |  |  |  |  |  |  | } | 
| 636 |  |  |  |  |  |  | else { | 
| 637 | 20 | 50 |  |  |  | 41 | if ($done) { | 
| 638 | 0 |  |  |  |  | 0 | $errmsg = "Error in field '$fieldname':  " . | 
| 639 |  |  |  |  |  |  | "DEFAULT must be the last condition listed."; | 
| 640 | 0 |  |  |  |  | 0 | return; | 
| 641 |  |  |  |  |  |  | } | 
| 642 | 20 |  |  |  |  | 407 | $condition =~ s/<<(.*?)>>/\$retval{$1}/g; | 
| 643 | 20 |  |  |  |  | 46 | $code .= "  elsif ($condition) {\n"; | 
| 644 | 20 |  |  |  |  | 239 | $code .= "    print \"Field $fieldname, inside branch number $branchno\\n\" if \$debug;\n"; | 
| 645 | 20 |  |  |  |  | 32 | $branchno++; | 
| 646 |  |  |  |  |  |  | } | 
| 647 |  |  |  |  |  |  |  | 
| 648 | 33 |  |  |  |  | 39 | my $retry_clause; | 
| 649 | 33 |  |  |  |  | 51 | my $indent = '    '; | 
| 650 | 33 | 100 |  |  |  | 128 | if (exists $hash->{Retry_If}) { | 
| 651 | 8 |  |  |  |  | 226 | $retry_clause = '(' | 
| 652 | 8 |  |  |  |  | 17 | . join(') || (', @{$hash->{Retry_If}}) | 
| 653 |  |  |  |  |  |  | . ')'; | 
| 654 | 8 |  |  |  |  | 298 | $retry_clause =~ s/<<(.*?)>>/\$retval{$1}/g; | 
| 655 | 8 |  |  |  |  | 305 | $retry_code .= "    if ($retry_clause) {\n"; | 
| 656 | 8 |  |  |  |  | 15 | $retry_code .= "      print \"  rejected\\n\" if \$debug;\n"; | 
| 657 | 8 |  |  |  |  | 14 | $retry_code .= "      next;\n"; | 
| 658 | 8 |  |  |  |  | 14 | $retry_code .= "    }\n"; | 
| 659 |  |  |  |  |  |  | #$code .= _retry_if_start_for_permutations($retry_clause, | 
| 660 |  |  |  |  |  |  | #                                          $fieldname, | 
| 661 |  |  |  |  |  |  | #                                          $indent); | 
| 662 | 8 |  |  |  |  | 13 | $indent .= '    '; | 
| 663 |  |  |  |  |  |  | } | 
| 664 |  |  |  |  |  |  |  | 
| 665 | 33 |  |  |  |  | 176 | my $temp_code; | 
| 666 | 33 | 100 |  |  |  | 164 | if (ref $hash->{Alternatives}[0] eq '') { | 
|  |  | 50 |  |  |  |  |  | 
| 667 |  |  |  |  |  |  | # In the form [1..15] or ['one', 'two', 'three'] | 
| 668 | 21 |  |  |  |  | 111 | $temp_code = Data::Dumper->Dump([$hash->{Alternatives}], ['$stuff']); | 
| 669 |  |  |  |  |  |  | } | 
| 670 |  |  |  |  |  |  | elsif (ref $hash->{Alternatives}[0] eq 'HASH') { | 
| 671 | 12 |  |  |  |  | 15 | my @array; | 
| 672 | 12 |  |  |  |  | 17 | foreach my $index (0..$#{$hash->{Alternatives}}) { | 
|  | 12 |  |  |  |  | 44 |  | 
| 673 | 24 |  |  |  |  | 47 | my $ary = $hash->{Alternatives}[$index]; | 
| 674 | 24 |  |  |  |  | 25 | push @array, @{$ary->{Data}}; | 
|  | 24 |  |  |  |  | 167 |  | 
| 675 |  |  |  |  |  |  | } | 
| 676 | 12 |  |  |  |  | 428 | $temp_code = Data::Dumper->Dump([\@array], ['$stuff']); | 
| 677 |  |  |  |  |  |  | } | 
| 678 |  |  |  |  |  |  | else { | 
| 679 | 0 |  |  |  |  | 0 | $errmsg = "Error in Field '$fieldname'.  " . | 
| 680 |  |  |  |  |  |  | "First element of the conditional Alternatives " . | 
| 681 |  |  |  |  |  |  | "array is neither a scalar nor an array."; | 
| 682 | 0 |  |  |  |  | 0 | return; | 
| 683 |  |  |  |  |  |  | } | 
| 684 | 33 |  |  |  |  | 3402 | $temp_code =~ s/^/$indent/mg; | 
| 685 | 33 |  |  |  |  | 62 | $code .= $temp_code; | 
| 686 | 33 |  |  |  |  | 90 | $code .= "  }\n"; | 
| 687 |  |  |  |  |  |  | } | 
| 688 | 13 |  |  |  |  | 28 | $code .= "  foreach my \$thingy (\@\$stuff) {\n"; | 
| 689 | 13 |  |  |  |  | 21 | $code .= "    my \$stuff;\n"; | 
| 690 | 13 |  |  |  |  | 27 | $code .= "    \$retval{$fieldname} = \$thingy;\n"; | 
| 691 | 13 |  |  |  |  | 42 | $code .= "    print \"$fieldname just set to \$retval{$fieldname}\\n\" if \$debug;\n\n"; | 
| 692 | 13 |  |  |  |  | 29 | $fieldnames[$nestlevel] = $fieldname; | 
| 693 | 13 |  |  |  |  | 41 | $nestlevel++; | 
| 694 |  |  |  |  |  |  | } | 
| 695 |  |  |  |  |  |  | else { | 
| 696 |  |  |  |  |  |  | # In the form [{Data   => [1..5], | 
| 697 |  |  |  |  |  |  | #               Weight => 1}, | 
| 698 |  |  |  |  |  |  | #              {Data   => [6..10], | 
| 699 |  |  |  |  |  |  | #               Weight => 2}] | 
| 700 | 2 |  |  |  |  | 4 | my @array; | 
| 701 | 2 |  |  |  |  | 3 | foreach my $index (0..$#{$rules->[$i]{Values}}) { | 
|  | 2 |  |  |  |  | 7 |  | 
| 702 | 5 |  |  |  |  | 11 | my $ary = $rules->[$i]{Values}[$index]; | 
| 703 | 5 |  |  |  |  | 6 | push @array, @{$ary->{Data}}; | 
|  | 5 |  |  |  |  | 23 |  | 
| 704 |  |  |  |  |  |  | } | 
| 705 | 2 |  |  |  |  | 15 | my $temp_code = Data::Dumper->Dump([\@array], ['$stuff']); | 
| 706 | 2 |  |  |  |  | 178 | $temp_code =~ s/^/$outer_indent/mg; | 
| 707 | 2 |  |  |  |  | 9 | $code .= $outer_indent . "if (\$parms{$fieldname}) {\n"; | 
| 708 | 2 |  |  |  |  | 5 | $code .= $outer_indent . "  \$stuff = [\"\$parms{$fieldname}\"];\n"; | 
| 709 | 2 |  |  |  |  | 5 | $code .= $outer_indent . "}\n"; | 
| 710 | 2 |  |  |  |  | 2 | $code .= $outer_indent . "else {\n"; | 
| 711 | 2 |  |  |  |  | 5 | $code .= $temp_code; | 
| 712 | 2 |  |  |  |  | 4 | $code .= $outer_indent . "}\n"; | 
| 713 | 2 |  |  |  |  | 5 | $code .= $outer_indent . "foreach my \$thingy (\@\$stuff) {\n"; | 
| 714 | 2 |  |  |  |  | 6 | $code .= $outer_indent . "  \$retval{$fieldname} = \$thingy;\n"; | 
| 715 | 2 |  |  |  |  | 6 | $code .= $outer_indent . "  print \"$fieldname just set to \$retval{$fieldname}\\n\" if \$debug;\n\n"; | 
| 716 | 2 |  |  |  |  | 5 | $fieldnames[$nestlevel] = $fieldname; | 
| 717 | 2 |  |  |  |  | 10 | $nestlevel++; | 
| 718 |  |  |  |  |  |  | } | 
| 719 |  |  |  |  |  |  | } | 
| 720 |  |  |  |  |  |  | else { | 
| 721 | 0 |  |  |  |  | 0 | $errmsg = "Error in field '$fieldname':  " . | 
| 722 |  |  |  |  |  |  | "First element of Values is neither a scalar nor a hash."; | 
| 723 | 0 |  |  |  |  | 0 | return; | 
| 724 |  |  |  |  |  |  | } | 
| 725 |  |  |  |  |  |  | } | 
| 726 |  |  |  |  |  |  | else { | 
| 727 | 0 |  |  |  |  | 0 | $errmsg = "Error in field '$fieldname':  " . | 
| 728 |  |  |  |  |  |  | "Values element should be an array."; | 
| 729 | 0 |  |  |  |  | 0 | return; | 
| 730 |  |  |  |  |  |  | } | 
| 731 |  |  |  |  |  |  | } | 
| 732 |  |  |  |  |  |  |  | 
| 733 | 17 |  |  |  |  | 40 | $code .= $retry_code; | 
| 734 | 17 |  |  |  |  | 35 | $code .= "  if (\$count_or_generate eq 'count') {\n"; | 
| 735 | 17 |  |  |  |  | 41 | $code .= "    \$permutations++;\n"; | 
| 736 | 17 |  |  |  |  | 27 | $code .= "  }\n"; | 
| 737 | 17 |  |  |  |  | 30 | $code .= "  else {\n"; | 
| 738 | 17 |  |  |  |  | 23 | $code .= "    push \@retlist, {\%retval};\n"; | 
| 739 | 17 |  |  |  |  | 89 | $code .= "  }\n"; | 
| 740 |  |  |  |  |  |  |  | 
| 741 | 17 |  |  |  |  | 219 | while ($nestlevel) { | 
| 742 | 28 |  |  |  |  | 35 | $nestlevel--; | 
| 743 | 28 |  |  |  |  | 539 | $code .= "delete \$retval{$fieldnames[$nestlevel]};\n"; | 
| 744 | 28 |  |  |  |  | 65 | $code .= "}\n"; | 
| 745 |  |  |  |  |  |  | } | 
| 746 | 17 |  |  |  |  | 26 | $code .= "\n\n"; | 
| 747 | 17 |  |  |  |  | 29 | $code .= "  return \$count_or_generate eq 'count' ? \$permutations\n"; | 
| 748 | 17 |  |  |  |  | 23 | $code .= "                                       : \@retlist;\n"; | 
| 749 | 17 |  |  |  |  | 25 | $code .= "}\n"; | 
| 750 |  |  |  |  |  |  |  | 
| 751 | 17 | 100 |  |  |  | 53 | if ($print_filename) { | 
| 752 | 2 | 50 |  |  |  | 180 | if (open CODE, ">>$print_filename") { | 
| 753 | 2 |  |  |  |  | 18 | print CODE "\n\n\n# permutations() and generate_all() method\n\n", $code; | 
| 754 | 2 |  |  |  |  | 69 | close CODE; | 
| 755 |  |  |  |  |  |  | } | 
| 756 |  |  |  |  |  |  | else { | 
| 757 | 0 |  |  |  |  | 0 | print STDERR "Failed to open $print_filename for append: $!"; | 
| 758 |  |  |  |  |  |  | } | 
| 759 |  |  |  |  |  |  | } | 
| 760 |  |  |  |  |  |  |  | 
| 761 | 17 |  |  |  |  | 10260 | my $retval = eval $code; | 
| 762 | 17 | 50 |  |  |  | 95 | unless (defined $retval) { | 
| 763 | 0 |  |  |  |  | 0 | $errmsg = $@; | 
| 764 | 0 |  |  |  |  | 0 | return; | 
| 765 |  |  |  |  |  |  | } | 
| 766 | 17 |  |  |  |  | 106 | return $retval; | 
| 767 |  |  |  |  |  |  | } | 
| 768 |  |  |  |  |  |  |  | 
| 769 |  |  |  |  |  |  |  | 
| 770 |  |  |  |  |  |  | =head1 new | 
| 771 |  |  |  |  |  |  |  | 
| 772 |  |  |  |  |  |  | =head2 Description | 
| 773 |  |  |  |  |  |  |  | 
| 774 |  |  |  |  |  |  | This is the constructor for Randomize objects.  It takes one parameter: | 
| 775 |  |  |  |  |  |  | a reference to an array containing randomizer rules.  From these rules, | 
| 776 |  |  |  |  |  |  | the generate() and permutations() methods are created.  If an error is | 
| 777 |  |  |  |  |  |  | detected in the rules, the package variable $Randomize::errmsg will contain | 
| 778 |  |  |  |  |  |  | the error message and new() will return undef. | 
| 779 |  |  |  |  |  |  |  | 
| 780 |  |  |  |  |  |  | =head2 Syntax | 
| 781 |  |  |  |  |  |  |  | 
| 782 |  |  |  |  |  |  | $randomizer = Randomize->new(\@rules); | 
| 783 |  |  |  |  |  |  |  | 
| 784 |  |  |  |  |  |  | $randomizer  - On success, a Randomize object.  On failure, undef | 
| 785 |  |  |  |  |  |  | is returned and $Randomize::errmsg will contain a | 
| 786 |  |  |  |  |  |  | descriptive error message. | 
| 787 |  |  |  |  |  |  |  | 
| 788 |  |  |  |  |  |  | \@rules      - A reference to an array containing Randomize rules, | 
| 789 |  |  |  |  |  |  | as described in the DESCRIPTION section. | 
| 790 |  |  |  |  |  |  |  | 
| 791 |  |  |  |  |  |  | =cut | 
| 792 |  |  |  |  |  |  |  | 
| 793 |  |  |  |  |  |  | sub new { | 
| 794 | 30 |  |  | 30 | 0 | 7819 | my ($class, $rules) = @_; | 
| 795 | 30 |  |  |  |  | 67 | $errmsg = ''; | 
| 796 | 30 | 50 |  |  |  | 93 | $errmsg = "No class specified", return unless $class; | 
| 797 | 30 | 50 |  |  |  | 83 | $errmsg = "No rules specified", return unless $rules; | 
| 798 | 30 | 50 |  |  |  | 100 | $errmsg = "\$rules is not an array ref", return | 
| 799 |  |  |  |  |  |  | unless ref $rules eq 'ARRAY'; | 
| 800 |  |  |  |  |  |  |  | 
| 801 | 30 |  |  |  |  | 52 | my $self = {}; | 
| 802 |  |  |  |  |  |  |  | 
| 803 | 30 | 100 |  |  |  | 85 | return unless $self->{Generate} = _create_generate_method($rules); | 
| 804 |  |  |  |  |  |  |  | 
| 805 | 17 | 50 |  |  |  | 57 | return unless $self->{Permutations_and_Generate_All} = | 
| 806 |  |  |  |  |  |  | _create_permutations_generateall_method($rules); | 
| 807 |  |  |  |  |  |  |  | 
| 808 |  |  |  |  |  |  |  | 
| 809 | 17 |  |  |  |  | 98 | bless $self, $class; | 
| 810 |  |  |  |  |  |  |  | 
| 811 |  |  |  |  |  |  | } # new | 
| 812 |  |  |  |  |  |  |  | 
| 813 |  |  |  |  |  |  |  | 
| 814 |  |  |  |  |  |  |  | 
| 815 |  |  |  |  |  |  |  | 
| 816 |  |  |  |  |  |  | ################################################################## | 
| 817 |  |  |  |  |  |  | # | 
| 818 |  |  |  |  |  |  | # _retry_if_start_for_generate | 
| 819 |  |  |  |  |  |  | # | 
| 820 |  |  |  |  |  |  | # Generates code for the Retry_If clause for the generate method. | 
| 821 |  |  |  |  |  |  | # | 
| 822 |  |  |  |  |  |  | # Syntax: | 
| 823 |  |  |  |  |  |  | # | 
| 824 |  |  |  |  |  |  | #   $code = _retry_if_start_for_generate($retry_clause, $fieldname, $indent); | 
| 825 |  |  |  |  |  |  |  | 
| 826 |  |  |  |  |  |  | sub _retry_if_start_for_generate { | 
| 827 | 26 |  |  | 26 |  | 49 | my ($retry_clause, $fieldname, $indent) = @_; | 
| 828 |  |  |  |  |  |  |  | 
| 829 | 26 |  |  |  |  | 40 | my $code = ''; | 
| 830 | 26 |  |  |  |  | 57 | $code .= "if (exists  \$retval{$fieldname}) {\n"; | 
| 831 | 26 |  |  |  |  | 64 | $code .= "  print \"The user specified a value for $fieldname\\n\" if \$debug;\n"; | 
| 832 | 26 |  |  |  |  | 55 | $code .= "  if ($retry_clause) {\n"; | 
| 833 | 26 |  |  |  |  | 72 | $code .= "    die \"The user-specified value for $fieldname violates the Retry_If rule.\"\n"; | 
| 834 | 26 |  |  |  |  | 39 | $code .= "  }\n"; | 
| 835 | 26 |  |  |  |  | 28 | $code .= "}\n"; | 
| 836 | 26 |  |  |  |  | 39 | $code .= "else {\n"; | 
| 837 | 26 |  |  |  |  | 124 | $code .= "  my \$done = 0;\n"; | 
| 838 | 26 |  |  |  |  | 30 | $code .= "  while (!\$done) {\n"; | 
| 839 | 26 |  |  |  |  | 83 | $code .= "    print \"Getting ready to choose a value for $fieldname\\n\" if \$debug;\n"; | 
| 840 | 26 |  |  |  |  | 36 | $code .= "    \$counter++;\n"; | 
| 841 | 26 |  |  |  |  | 747 | $code =~ s/^/$indent/mg; | 
| 842 |  |  |  |  |  |  |  | 
| 843 | 26 |  |  |  |  | 77 | return $code; | 
| 844 |  |  |  |  |  |  | } | 
| 845 |  |  |  |  |  |  |  | 
| 846 |  |  |  |  |  |  |  | 
| 847 |  |  |  |  |  |  |  | 
| 848 |  |  |  |  |  |  |  | 
| 849 |  |  |  |  |  |  | ################################################################## | 
| 850 |  |  |  |  |  |  | # | 
| 851 |  |  |  |  |  |  | # _retry_if_finish_for_generate | 
| 852 |  |  |  |  |  |  | # | 
| 853 |  |  |  |  |  |  | # Generates code for the Retry_If clause for the generate method. | 
| 854 |  |  |  |  |  |  | # | 
| 855 |  |  |  |  |  |  | # Syntax: | 
| 856 |  |  |  |  |  |  | # | 
| 857 |  |  |  |  |  |  | #   $code = _retry_if_finish_for_generate($retry_clause, $fieldname, $indent); | 
| 858 |  |  |  |  |  |  |  | 
| 859 |  |  |  |  |  |  | sub _retry_if_finish_for_generate { | 
| 860 | 22 |  |  | 22 |  | 46 | my ($retry_clause, $fieldname, $indent) = @_; | 
| 861 | 22 |  |  |  |  | 54 | my $code = $indent . "\$retval{$fieldname} = \$stuff->[rand \@\$stuff];\n"; | 
| 862 | 22 |  |  |  |  | 76 | $code .= $indent . "print \"$fieldname just set to \", Dumper(\$retval{$fieldname}), \"\\n\" if \$debug;\n\n"; | 
| 863 | 22 |  |  |  |  | 61 | $code .= $indent . "if ($retry_clause) {\n"; | 
| 864 | 22 |  |  |  |  | 121 | $code .= $indent . "  print \"Gonna have to retry\\n\" if \$debug;\n"; | 
| 865 | 22 |  |  |  |  | 40 | $code .= $indent . "  die <= 100;\n"; | 
| 866 | 22 |  |  |  |  | 43 | $code .= "Couldn't find a usable value for $fieldname in 100 tries.\n"; | 
| 867 | 22 |  |  |  |  | 34 | $code .= "Maybe your retry clauses are too restrictive.\n"; | 
| 868 | 22 |  |  |  |  | 65 | $code .= "EOT\n"; | 
| 869 | 22 |  |  |  |  | 30 | $code .= $indent . "}\n"; | 
| 870 | 22 |  |  |  |  | 32 | $code .= $indent . "else {\n"; | 
| 871 | 22 |  |  |  |  | 45 | $code .= $indent . "  print \"Passed the retry clause.\\n\" if \$debug;\n"; | 
| 872 | 22 |  |  |  |  | 32 | $code .= $indent . "  \$done = 1;\n"; | 
| 873 | 22 |  |  |  |  | 32 | $code .= $indent . "}\n"; | 
| 874 | 22 |  |  |  |  | 62 | $code .= substr($indent, 0, length($indent)-2) . "}\n"; | 
| 875 | 22 |  |  |  |  | 47 | $code .= substr($indent, 0, length($indent)-4) . "}\n"; | 
| 876 | 22 |  |  |  |  | 77 | return $code; | 
| 877 |  |  |  |  |  |  | } | 
| 878 |  |  |  |  |  |  |  | 
| 879 |  |  |  |  |  |  |  | 
| 880 |  |  |  |  |  |  |  | 
| 881 |  |  |  |  |  |  |  | 
| 882 |  |  |  |  |  |  | ################################################################## | 
| 883 |  |  |  |  |  |  | # | 
| 884 |  |  |  |  |  |  | # _retry_if_start_for_permutations | 
| 885 |  |  |  |  |  |  | # | 
| 886 |  |  |  |  |  |  | # Generates code for the Retry_If clause for the permutations method. | 
| 887 |  |  |  |  |  |  | # | 
| 888 |  |  |  |  |  |  | # Syntax: | 
| 889 |  |  |  |  |  |  | # | 
| 890 |  |  |  |  |  |  | #   $code = _retry_if_start_for_permutations($retry_clause, $fieldname, $indent); | 
| 891 |  |  |  |  |  |  |  | 
| 892 |  |  |  |  |  |  | sub _retry_if_start_for_permutations { | 
| 893 | 0 |  |  | 0 |  | 0 | my ($retry_clause, $fieldname, $indent) = @_; | 
| 894 |  |  |  |  |  |  |  | 
| 895 | 0 |  |  |  |  | 0 | my $code = ''; | 
| 896 | 0 |  |  |  |  | 0 | $code .= "if (exists  \$retval{$fieldname}) {\n"; | 
| 897 | 0 |  |  |  |  | 0 | $code .= "  print \"The user specified a value for $fieldname\\n\" if \$debug;\n"; | 
| 898 | 0 |  |  |  |  | 0 | $code .= "  if ($retry_clause) {\n"; | 
| 899 | 0 |  |  |  |  | 0 | $code .= "    die \"The user-specified value for $fieldname violates the Retry_If rule.\"\n"; | 
| 900 | 0 |  |  |  |  | 0 | $code .= "  }\n"; | 
| 901 | 0 |  |  |  |  | 0 | $code .= "}\n"; | 
| 902 | 0 |  |  |  |  | 0 | $code .= "else {\n"; | 
| 903 | 0 |  |  |  |  | 0 | $code =~ s/^/$indent/mg; | 
| 904 |  |  |  |  |  |  |  | 
| 905 | 0 |  |  |  |  | 0 | return $code; | 
| 906 |  |  |  |  |  |  | } | 
| 907 |  |  |  |  |  |  |  | 
| 908 |  |  |  |  |  |  |  | 
| 909 |  |  |  |  |  |  | =head1 generate | 
| 910 |  |  |  |  |  |  |  | 
| 911 |  |  |  |  |  |  | =head2 Description | 
| 912 |  |  |  |  |  |  |  | 
| 913 |  |  |  |  |  |  | This method returns a reference to a hash.  The hash contains the fields | 
| 914 |  |  |  |  |  |  | you specified in your randomizer rules.  Each call to generate() gives you | 
| 915 |  |  |  |  |  |  | a new hash, with a new set of randomized values. | 
| 916 |  |  |  |  |  |  |  | 
| 917 |  |  |  |  |  |  | NOTE:  If you wish to specify a value for one or more fields of the hash, | 
| 918 |  |  |  |  |  |  | you can pass in the field and its value. | 
| 919 |  |  |  |  |  |  |  | 
| 920 |  |  |  |  |  |  | =head2 Syntax | 
| 921 |  |  |  |  |  |  |  | 
| 922 |  |  |  |  |  |  | $hashref = $randomizer->generate( [ $fieldname, $value, ... ] ); | 
| 923 |  |  |  |  |  |  |  | 
| 924 |  |  |  |  |  |  | $hashref    - A hash reference returned by generate(). | 
| 925 |  |  |  |  |  |  |  | 
| 926 |  |  |  |  |  |  | $randomizer - A Randomize object. | 
| 927 |  |  |  |  |  |  |  | 
| 928 |  |  |  |  |  |  | $fieldname  - The name of a field in the hash. | 
| 929 |  |  |  |  |  |  |  | 
| 930 |  |  |  |  |  |  | $value      - The value you wish that field to take | 
| 931 |  |  |  |  |  |  | this time through. | 
| 932 |  |  |  |  |  |  |  | 
| 933 |  |  |  |  |  |  | =cut | 
| 934 |  |  |  |  |  |  |  | 
| 935 |  |  |  |  |  |  |  | 
| 936 |  |  |  |  |  |  |  | 
| 937 |  |  |  |  |  |  | sub generate { | 
| 938 | 18056 |  |  | 18056 | 0 | 157200 | my $self = shift; | 
| 939 | 18056 |  |  |  |  | 26236 | &{$self->{Generate}}(@_); | 
|  | 18056 |  |  |  |  | 460056 |  | 
| 940 |  |  |  |  |  |  | } | 
| 941 |  |  |  |  |  |  |  | 
| 942 |  |  |  |  |  |  |  | 
| 943 |  |  |  |  |  |  | =head1 permutations | 
| 944 |  |  |  |  |  |  |  | 
| 945 |  |  |  |  |  |  | =head2 Description | 
| 946 |  |  |  |  |  |  |  | 
| 947 |  |  |  |  |  |  | This method returns the number of permutations of the hash you've | 
| 948 |  |  |  |  |  |  | specified. | 
| 949 |  |  |  |  |  |  |  | 
| 950 |  |  |  |  |  |  | NOTE:  If you wish to specify a value for one or more fields of the hash, | 
| 951 |  |  |  |  |  |  | you can pass in the field and its value. | 
| 952 |  |  |  |  |  |  |  | 
| 953 |  |  |  |  |  |  | =head2 Syntax | 
| 954 |  |  |  |  |  |  |  | 
| 955 |  |  |  |  |  |  | $permutations = $randomizer->permutations( [ $fieldname, $value, ... ] ); | 
| 956 |  |  |  |  |  |  |  | 
| 957 |  |  |  |  |  |  | $permutations - The exact number of permutations of the | 
| 958 |  |  |  |  |  |  | hash you've specified. | 
| 959 |  |  |  |  |  |  |  | 
| 960 |  |  |  |  |  |  | $randomizer   - A Randomize object. | 
| 961 |  |  |  |  |  |  |  | 
| 962 |  |  |  |  |  |  | $fieldname    - The name of a field in the hash. | 
| 963 |  |  |  |  |  |  |  | 
| 964 |  |  |  |  |  |  | $value        - The value you wish that field to take | 
| 965 |  |  |  |  |  |  | this time through. | 
| 966 |  |  |  |  |  |  |  | 
| 967 |  |  |  |  |  |  | =cut | 
| 968 |  |  |  |  |  |  |  | 
| 969 |  |  |  |  |  |  |  | 
| 970 |  |  |  |  |  |  |  | 
| 971 |  |  |  |  |  |  | sub permutations { | 
| 972 | 5 |  |  | 5 | 0 | 758 | my $self = shift; | 
| 973 | 5 |  |  |  |  | 12 | &{$self->{Permutations_and_Generate_All}}('count',@_); | 
|  | 5 |  |  |  |  | 350 |  | 
| 974 |  |  |  |  |  |  | } | 
| 975 |  |  |  |  |  |  |  | 
| 976 |  |  |  |  |  |  |  | 
| 977 |  |  |  |  |  |  |  | 
| 978 |  |  |  |  |  |  |  | 
| 979 |  |  |  |  |  |  |  | 
| 980 |  |  |  |  |  |  | =head1 generate_all | 
| 981 |  |  |  |  |  |  |  | 
| 982 |  |  |  |  |  |  | =head2 Description | 
| 983 |  |  |  |  |  |  |  | 
| 984 |  |  |  |  |  |  | This method returns a list containing every permutation of the hash you've | 
| 985 |  |  |  |  |  |  | specified. | 
| 986 |  |  |  |  |  |  |  | 
| 987 |  |  |  |  |  |  | NOTE:  If you wish to specify a value for one or more fields of the hash, | 
| 988 |  |  |  |  |  |  | you can pass in the field and its value. | 
| 989 |  |  |  |  |  |  |  | 
| 990 |  |  |  |  |  |  | =head2 Syntax | 
| 991 |  |  |  |  |  |  |  | 
| 992 |  |  |  |  |  |  | @permutations = $randomizer->generate_all( [ $fieldname, $value, ... ] ); | 
| 993 |  |  |  |  |  |  |  | 
| 994 |  |  |  |  |  |  | @permutations - A list containing every possible permutation | 
| 995 |  |  |  |  |  |  | of the hash you've specified. | 
| 996 |  |  |  |  |  |  |  | 
| 997 |  |  |  |  |  |  | $randomizer   - A Randomize object. | 
| 998 |  |  |  |  |  |  |  | 
| 999 |  |  |  |  |  |  | $fieldname    - The name of a field in the hash. | 
| 1000 |  |  |  |  |  |  |  | 
| 1001 |  |  |  |  |  |  | $value        - The value you wish that field to take | 
| 1002 |  |  |  |  |  |  | this time through. | 
| 1003 |  |  |  |  |  |  |  | 
| 1004 |  |  |  |  |  |  | =cut | 
| 1005 |  |  |  |  |  |  |  | 
| 1006 |  |  |  |  |  |  |  | 
| 1007 |  |  |  |  |  |  |  | 
| 1008 |  |  |  |  |  |  | sub generate_all { | 
| 1009 | 5 |  |  | 5 | 0 | 1934 | my $self = shift; | 
| 1010 | 5 |  |  |  |  | 13 | &{$self->{Permutations_and_Generate_All}}('generate',@_); | 
|  | 5 |  |  |  |  | 235 |  | 
| 1011 |  |  |  |  |  |  | } | 
| 1012 |  |  |  |  |  |  |  | 
| 1013 |  |  |  |  |  |  | 1; | 
| 1014 |  |  |  |  |  |  |  |