| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package App::Followme::BaseData; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 20 |  |  | 20 |  | 2287 | use 5.008005; | 
|  | 20 |  |  |  |  | 84 |  | 
| 4 | 20 |  |  | 20 |  | 112 | use strict; | 
|  | 20 |  |  |  |  | 44 |  | 
|  | 20 |  |  |  |  | 502 |  | 
| 5 | 20 |  |  | 20 |  | 110 | use warnings; | 
|  | 20 |  |  |  |  | 47 |  | 
|  | 20 |  |  |  |  | 564 |  | 
| 6 | 20 |  |  | 20 |  | 732 | use integer; | 
|  | 20 |  |  |  |  | 53 |  | 
|  | 20 |  |  |  |  | 116 |  | 
| 7 | 20 |  |  | 20 |  | 1139 | use lib '../..'; | 
|  | 20 |  |  |  |  | 680 |  | 
|  | 20 |  |  |  |  | 94 |  | 
| 8 |  |  |  |  |  |  |  | 
| 9 | 20 |  |  | 20 |  | 2654 | use base qw(App::Followme::ConfiguredObject); | 
|  | 20 |  |  |  |  | 41 |  | 
|  | 20 |  |  |  |  | 5023 |  | 
| 10 | 20 |  |  | 20 |  | 669 | use App::Followme::FIO; | 
|  | 20 |  |  |  |  | 47 |  | 
|  | 20 |  |  |  |  | 52141 |  | 
| 11 |  |  |  |  |  |  |  | 
| 12 |  |  |  |  |  |  | #---------------------------------------------------------------------- | 
| 13 |  |  |  |  |  |  | # Default values of parameters | 
| 14 |  |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  | sub parameters { | 
| 16 | 368 |  |  | 368 | 1 | 631 | my ($pkg) = @_; | 
| 17 |  |  |  |  |  |  |  | 
| 18 |  |  |  |  |  |  | return ( | 
| 19 | 368 |  |  |  |  | 1126 | list_length => 5, | 
| 20 |  |  |  |  |  |  | target_prefix => 'target', | 
| 21 |  |  |  |  |  |  | ); | 
| 22 |  |  |  |  |  |  | } | 
| 23 |  |  |  |  |  |  |  | 
| 24 |  |  |  |  |  |  | #---------------------------------------------------------------------- | 
| 25 |  |  |  |  |  |  | # Build a new variable value given its name and context | 
| 26 |  |  |  |  |  |  |  | 
| 27 |  |  |  |  |  |  | sub build { | 
| 28 | 510 |  |  | 510 | 1 | 28375 | my ($self, $variable_name, $item, $loop) = @_; | 
| 29 |  |  |  |  |  |  |  | 
| 30 |  |  |  |  |  |  | # Extract the sigil from the variable name, if present | 
| 31 | 510 |  |  |  |  | 1308 | my ($sigil, $name) = $self->split_name($variable_name); | 
| 32 |  |  |  |  |  |  |  | 
| 33 |  |  |  |  |  |  | # Extract the sort field from the variable name | 
| 34 | 510 |  |  |  |  | 916 | my ($data_field, $sort_field, $sort_reverse); | 
| 35 | 510 |  |  |  |  | 1524 | ($data_field, $sort_field) = split('_by_', $name); | 
| 36 | 510 | 100 |  |  |  | 1237 | if (defined $sort_field) { | 
| 37 | 56 | 100 |  |  |  | 185 | if ($sort_field =~ s/_reversed$//) { | 
| 38 | 20 |  |  |  |  | 46 | $sort_reverse = 1; | 
| 39 |  |  |  |  |  |  | } else { | 
| 40 | 36 |  |  |  |  | 51 | $sort_reverse = 0; | 
| 41 |  |  |  |  |  |  | } | 
| 42 |  |  |  |  |  |  | } | 
| 43 |  |  |  |  |  |  |  | 
| 44 | 510 |  |  |  |  | 848 | my %cache = (); | 
| 45 | 510 | 100 |  |  |  | 1150 | if ($sigil eq '$') { | 
| 46 | 273 | 100 | 100 |  |  | 1514 | if (defined $item && | 
|  |  |  | 100 |  |  |  |  | 
| 47 |  |  |  |  |  |  | (! $self->{cache}{item} || $self->{cache}{item} ne $item)) { | 
| 48 |  |  |  |  |  |  | # Clear cache when argument to build changes | 
| 49 | 68 |  |  |  |  | 222 | %cache = (item => $item); | 
| 50 |  |  |  |  |  |  | } else { | 
| 51 | 205 |  |  |  |  | 343 | %cache = %{$self->{cache}}; | 
|  | 205 |  |  |  |  | 992 |  | 
| 52 |  |  |  |  |  |  | } | 
| 53 |  |  |  |  |  |  | } | 
| 54 |  |  |  |  |  |  |  | 
| 55 |  |  |  |  |  |  | # Build the value associated with a name if it is not in the cache | 
| 56 | 510 | 100 |  |  |  | 1338 | unless (exists $cache{$data_field}) { | 
| 57 | 423 |  |  |  |  | 1318 | my %data = $self->fetch_data($data_field, $item, $loop); | 
| 58 |  |  |  |  |  |  |  | 
| 59 | 423 |  |  |  |  | 867 | my $sorted_order = 0; | 
| 60 | 423 |  |  |  |  | 1136 | my $sorted_data = $self->sort(\%data, $sort_field, $sort_reverse); | 
| 61 | 423 |  |  |  |  | 1152 | $sorted_data = $self->format($sorted_order, $sorted_data); | 
| 62 |  |  |  |  |  |  |  | 
| 63 | 423 |  |  |  |  | 2135 | %cache = (%cache, %$sorted_data); | 
| 64 |  |  |  |  |  |  | } | 
| 65 |  |  |  |  |  |  |  | 
| 66 |  |  |  |  |  |  | # Check the value for agreement with the sigil and return reference | 
| 67 | 510 |  |  |  |  | 1472 | my $ref_value = $self->ref_value($cache{$data_field}, $sigil, $data_field); | 
| 68 | 510 | 100 |  |  |  | 1583 | $self->{cache} = \%cache if $sigil eq '$'; | 
| 69 | 510 |  |  |  |  | 9731 | return $ref_value; | 
| 70 |  |  |  |  |  |  | } | 
| 71 |  |  |  |  |  |  |  | 
| 72 |  |  |  |  |  |  | #---------------------------------------------------------------------- | 
| 73 |  |  |  |  |  |  | # Coerce the data to a hash | 
| 74 |  |  |  |  |  |  |  | 
| 75 |  |  |  |  |  |  | sub coerce_data { | 
| 76 | 715 |  |  | 715 | 0 | 3263 | my ($self, $name, @data) = @_; | 
| 77 |  |  |  |  |  |  |  | 
| 78 | 715 |  |  |  |  | 1037 | my %data; | 
| 79 | 715 | 100 |  |  |  | 1833 | if (@data == 0) { | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 80 | 156 |  |  |  |  | 271 | %data = (); | 
| 81 |  |  |  |  |  |  |  | 
| 82 |  |  |  |  |  |  | } elsif (@data == 1) { | 
| 83 | 558 |  |  |  |  | 1420 | %data = ($name => $data[0]); | 
| 84 |  |  |  |  |  |  |  | 
| 85 |  |  |  |  |  |  | } elsif (@data % 2 == 0) { | 
| 86 | 1 |  |  |  |  | 3 | %data = @data; | 
| 87 |  |  |  |  |  |  |  | 
| 88 |  |  |  |  |  |  | } else { | 
| 89 | 0 |  |  |  |  | 0 | my $pkg = ref $self; | 
| 90 | 0 |  |  |  |  | 0 | die "$name does not return a hash\n"; | 
| 91 |  |  |  |  |  |  | } | 
| 92 |  |  |  |  |  |  |  | 
| 93 | 715 |  |  |  |  | 2312 | return %data; | 
| 94 |  |  |  |  |  |  | } | 
| 95 |  |  |  |  |  |  |  | 
| 96 |  |  |  |  |  |  | #---------------------------------------------------------------------- | 
| 97 |  |  |  |  |  |  | # Fetch the data for building a variable's value | 
| 98 |  |  |  |  |  |  |  | 
| 99 |  |  |  |  |  |  | sub fetch_data { | 
| 100 | 29 |  |  | 29 | 0 | 60 | my ($self, $name, $item, $loop) = @_; | 
| 101 |  |  |  |  |  |  |  | 
| 102 | 29 |  |  |  |  | 60 | my %data = $self->gather_data('get', $name, $item, $loop); | 
| 103 | 29 |  |  |  |  | 112 | return %data; | 
| 104 |  |  |  |  |  |  | } | 
| 105 |  |  |  |  |  |  |  | 
| 106 |  |  |  |  |  |  | #---------------------------------------------------------------------- | 
| 107 |  |  |  |  |  |  | # Choose the file comparison routine that matches the configuration | 
| 108 |  |  |  |  |  |  |  | 
| 109 |  |  |  |  |  |  | sub file_comparer { | 
| 110 | 172 |  |  | 172 | 0 | 339 | my ($self, $sort_reverse) = @_; | 
| 111 |  |  |  |  |  |  |  | 
| 112 | 172 |  |  |  |  | 241 | my $comparer; | 
| 113 | 172 | 100 |  |  |  | 330 | if ($sort_reverse) { | 
| 114 | 58 |  |  | 53 |  | 235 | $comparer = sub ($$) {$_[1]->[0] cmp $_[0]->[0]}; | 
|  | 53 |  |  |  |  | 135 |  | 
| 115 |  |  |  |  |  |  | } else { | 
| 116 | 114 |  |  | 105 |  | 516 | $comparer = sub ($$) {$_[0]->[0] cmp $_[1]->[0]}; | 
|  | 105 |  |  |  |  | 223 |  | 
| 117 |  |  |  |  |  |  | } | 
| 118 |  |  |  |  |  |  |  | 
| 119 | 172 |  |  |  |  | 369 | return $comparer; | 
| 120 |  |  |  |  |  |  | } | 
| 121 |  |  |  |  |  |  |  | 
| 122 |  |  |  |  |  |  | #---------------------------------------------------------------------- | 
| 123 |  |  |  |  |  |  | # If there is omly a single field containing data, return its name | 
| 124 |  |  |  |  |  |  |  | 
| 125 |  |  |  |  |  |  | sub find_data_field { | 
| 126 | 424 |  |  | 424 | 0 | 724 | my ($self, $data) = @_; | 
| 127 |  |  |  |  |  |  |  | 
| 128 | 424 |  |  |  |  | 965 | my @keys = keys %$data; | 
| 129 |  |  |  |  |  |  |  | 
| 130 | 424 |  |  |  |  | 595 | my $field; | 
| 131 | 424 | 100 |  |  |  | 985 | if (@keys == 1 ) { | 
| 132 | 315 |  |  |  |  | 495 | my $key = $keys[0]; | 
| 133 | 315 | 100 |  |  |  | 865 | if (ref $data->{$key} eq 'ARRAY') { | 
| 134 | 134 |  |  |  |  | 244 | $field = $key; | 
| 135 |  |  |  |  |  |  | } | 
| 136 |  |  |  |  |  |  | } | 
| 137 |  |  |  |  |  |  |  | 
| 138 | 424 |  |  |  |  | 954 | return $field; | 
| 139 |  |  |  |  |  |  | } | 
| 140 |  |  |  |  |  |  |  | 
| 141 |  |  |  |  |  |  | #---------------------------------------------------------------------- | 
| 142 |  |  |  |  |  |  | # Find the values to sort by and format them so they are in sort order | 
| 143 |  |  |  |  |  |  |  | 
| 144 |  |  |  |  |  |  | sub find_sort_column { | 
| 145 | 153 |  |  | 153 | 0 | 307 | my ($self, $data_column, $sort_field) = @_; | 
| 146 |  |  |  |  |  |  |  | 
| 147 | 153 |  |  |  |  | 416 | my $formatter = "format_$sort_field"; | 
| 148 | 153 | 100 |  |  |  | 721 | $formatter = "format_nothing" unless $self->can($formatter); | 
| 149 |  |  |  |  |  |  |  | 
| 150 | 153 |  |  |  |  | 266 | my @sort_column; | 
| 151 | 153 |  |  |  |  | 231 | my $sorted_order = 1; | 
| 152 |  |  |  |  |  |  |  | 
| 153 | 153 |  |  |  |  | 321 | for my $data_item (@$data_column) { | 
| 154 | 220 |  |  |  |  | 625 | my %data = $self->fetch_data($sort_field, $data_item, $data_column); | 
| 155 |  |  |  |  |  |  |  | 
| 156 | 220 | 50 |  |  |  | 513 | if (exists $data{$sort_field}) { | 
| 157 |  |  |  |  |  |  | push(@sort_column, $self->$formatter($sorted_order, | 
| 158 | 220 |  |  |  |  | 697 | $data{$sort_field})); | 
| 159 |  |  |  |  |  |  | } else { | 
| 160 | 0 |  |  |  |  | 0 | warn "Sort field not found: $sort_field"; | 
| 161 | 0 |  |  |  |  | 0 | push(@sort_column, $data_item); | 
| 162 |  |  |  |  |  |  | } | 
| 163 |  |  |  |  |  |  |  | 
| 164 |  |  |  |  |  |  | } | 
| 165 |  |  |  |  |  |  |  | 
| 166 | 153 |  |  |  |  | 450 | return \@sort_column; | 
| 167 |  |  |  |  |  |  | } | 
| 168 |  |  |  |  |  |  |  | 
| 169 |  |  |  |  |  |  | #---------------------------------------------------------------------- | 
| 170 |  |  |  |  |  |  | # Find the target, return the target plus an offset | 
| 171 |  |  |  |  |  |  |  | 
| 172 |  |  |  |  |  |  | sub find_target { | 
| 173 | 30 |  |  | 30 | 0 | 58 | my ($self, $offset, $item, $loop) = @_; | 
| 174 | 30 | 50 |  |  |  | 67 | die "Can't use \$target_* outside of for\n"  unless $loop; | 
| 175 |  |  |  |  |  |  |  | 
| 176 | 30 |  |  |  |  | 46 | my $match = -999; | 
| 177 | 30 |  |  |  |  | 79 | foreach my $i (0 .. @$loop) { | 
| 178 | 60 | 100 |  |  |  | 125 | if ($loop->[$i] eq $item) { | 
| 179 | 30 |  |  |  |  | 44 | $match = $i; | 
| 180 | 30 |  |  |  |  | 54 | last; | 
| 181 |  |  |  |  |  |  | } | 
| 182 |  |  |  |  |  |  | } | 
| 183 |  |  |  |  |  |  |  | 
| 184 | 30 |  |  |  |  | 53 | my $index = $match + $offset + 1; | 
| 185 | 30 | 100 | 100 |  |  | 114 | $index = 0 if $index < 1 || $index > @$loop; | 
| 186 | 30 | 100 |  |  |  | 122 | return $index ? $self->{target_prefix} . $index : ''; | 
| 187 |  |  |  |  |  |  | } | 
| 188 |  |  |  |  |  |  |  | 
| 189 |  |  |  |  |  |  | #---------------------------------------------------------------------- | 
| 190 |  |  |  |  |  |  | # Apply an optional format to the data | 
| 191 |  |  |  |  |  |  |  | 
| 192 |  |  |  |  |  |  | sub format { | 
| 193 | 425 |  |  | 425 | 0 | 4337 | my ($self, $sorted_order, $sorted_data) = @_; | 
| 194 |  |  |  |  |  |  |  | 
| 195 | 425 |  |  |  |  | 1160 | foreach my $name (keys %$sorted_data) { | 
| 196 | 848 | 100 |  |  |  | 1777 | next unless $sorted_data->{$name}; | 
| 197 |  |  |  |  |  |  |  | 
| 198 | 804 |  |  |  |  | 1681 | my $formatter = join('_', 'format', $name); | 
| 199 | 804 | 100 |  |  |  | 3408 | if ($self->can($formatter)) { | 
| 200 | 207 | 50 |  |  |  | 552 | if (ref $sorted_data->{$name} eq 'ARRAY') { | 
|  |  | 50 |  |  |  |  |  | 
| 201 | 0 |  |  |  |  | 0 | for my $value (@{$sorted_data->{$name}}) { | 
|  | 0 |  |  |  |  | 0 |  | 
| 202 | 0 |  |  |  |  | 0 | $value = $self->$formatter($sorted_order, | 
| 203 |  |  |  |  |  |  | $value); | 
| 204 |  |  |  |  |  |  | } | 
| 205 |  |  |  |  |  |  |  | 
| 206 |  |  |  |  |  |  | } elsif (ref $sorted_data->{$name} eq 'HASH') { | 
| 207 | 0 |  |  |  |  | 0 | die("Illegal data format for build: $name"); | 
| 208 |  |  |  |  |  |  |  | 
| 209 |  |  |  |  |  |  | } else { | 
| 210 |  |  |  |  |  |  | $sorted_data->{$name} = | 
| 211 | 207 |  |  |  |  | 672 | $self->$formatter($sorted_order, $sorted_data->{$name}); | 
| 212 |  |  |  |  |  |  | } | 
| 213 |  |  |  |  |  |  | } | 
| 214 |  |  |  |  |  |  | } | 
| 215 |  |  |  |  |  |  |  | 
| 216 | 425 |  |  |  |  | 904 | return $sorted_data; | 
| 217 |  |  |  |  |  |  | } | 
| 218 |  |  |  |  |  |  |  | 
| 219 |  |  |  |  |  |  | #---------------------------------------------------------------------- | 
| 220 |  |  |  |  |  |  | # Don't format anything | 
| 221 |  |  |  |  |  |  |  | 
| 222 |  |  |  |  |  |  | sub format_nothing { | 
| 223 | 7 |  |  | 7 | 0 | 12 | my ($self, $sorted_order, $value) = @_; | 
| 224 | 7 |  |  |  |  | 18 | return $value; | 
| 225 |  |  |  |  |  |  | } | 
| 226 |  |  |  |  |  |  |  | 
| 227 |  |  |  |  |  |  | #---------------------------------------------------------------------- | 
| 228 |  |  |  |  |  |  | # Gather the data for building a variable's value | 
| 229 |  |  |  |  |  |  |  | 
| 230 |  |  |  |  |  |  | sub gather_data { | 
| 231 | 712 |  |  | 712 | 0 | 1510 | my ($self, $method, $name, $item, $loop) = @_; | 
| 232 |  |  |  |  |  |  |  | 
| 233 | 712 |  |  |  |  | 1125 | my @data; | 
| 234 | 712 |  |  |  |  | 1486 | $method = join('_', $method, $name); | 
| 235 |  |  |  |  |  |  |  | 
| 236 | 712 | 100 |  |  |  | 3208 | if ($self->can($method)) { | 
| 237 | 557 |  |  |  |  | 1582 | @data = $self->$method($item, $loop); | 
| 238 |  |  |  |  |  |  |  | 
| 239 |  |  |  |  |  |  | } else { | 
| 240 | 155 |  |  |  |  | 283 | @data = (); | 
| 241 |  |  |  |  |  |  | } | 
| 242 |  |  |  |  |  |  |  | 
| 243 | 712 |  |  |  |  | 1940 | my %data = $self->coerce_data($name, @data); | 
| 244 | 712 |  |  |  |  | 2286 | return %data; | 
| 245 |  |  |  |  |  |  | } | 
| 246 |  |  |  |  |  |  |  | 
| 247 |  |  |  |  |  |  | #---------------------------------------------------------------------- | 
| 248 |  |  |  |  |  |  | # Get the count of the item in the list | 
| 249 |  |  |  |  |  |  |  | 
| 250 |  |  |  |  |  |  | sub get_count { | 
| 251 | 3 |  |  | 3 | 0 | 6 | my ($self, $item, $loop) = @_; | 
| 252 | 3 | 50 |  |  |  | 7 | die "Can't use \$count outside of for\n" unless $loop; | 
| 253 |  |  |  |  |  |  |  | 
| 254 | 3 |  |  |  |  | 10 | foreach my $i (0 .. @$loop) { | 
| 255 | 6 | 100 |  |  |  | 13 | if ($loop->[$i] eq $item) { | 
| 256 | 3 |  |  |  |  | 7 | my $count = $i + 1; | 
| 257 | 3 |  |  |  |  | 8 | return $count; | 
| 258 |  |  |  |  |  |  | } | 
| 259 |  |  |  |  |  |  | } | 
| 260 |  |  |  |  |  |  |  | 
| 261 | 0 |  |  |  |  | 0 | return; | 
| 262 |  |  |  |  |  |  | } | 
| 263 |  |  |  |  |  |  |  | 
| 264 |  |  |  |  |  |  | #---------------------------------------------------------------------- | 
| 265 |  |  |  |  |  |  | # Is this the first item in the list? | 
| 266 |  |  |  |  |  |  |  | 
| 267 |  |  |  |  |  |  | sub get_is_first { | 
| 268 | 3 |  |  | 3 | 0 | 7 | my ($self, $item, $loop) = @_; | 
| 269 |  |  |  |  |  |  |  | 
| 270 | 3 | 50 |  |  |  | 7 | die "Can't use \$is_first outside of for\n" unless $loop; | 
| 271 | 3 | 100 |  |  |  | 9 | return $loop->[0] eq $item ? 1 : 0; | 
| 272 |  |  |  |  |  |  | } | 
| 273 |  |  |  |  |  |  |  | 
| 274 |  |  |  |  |  |  | #---------------------------------------------------------------------- | 
| 275 |  |  |  |  |  |  | # Is this the last item in the list? | 
| 276 |  |  |  |  |  |  |  | 
| 277 |  |  |  |  |  |  | sub get_is_last { | 
| 278 | 3 |  |  | 3 | 0 | 5 | my ($self, $item, $loop) = @_; | 
| 279 |  |  |  |  |  |  |  | 
| 280 | 3 | 50 |  |  |  | 8 | die "Can't use \$is_last outside of for\n"  unless $loop; | 
| 281 | 3 | 100 |  |  |  | 8 | return $loop->[-1] eq $item ? 1 : 0; | 
| 282 |  |  |  |  |  |  | } | 
| 283 |  |  |  |  |  |  |  | 
| 284 |  |  |  |  |  |  | #---------------------------------------------------------------------- | 
| 285 |  |  |  |  |  |  | # Return the current list of loop items | 
| 286 |  |  |  |  |  |  |  | 
| 287 |  |  |  |  |  |  | sub get_loop { | 
| 288 | 1 |  |  | 1 | 0 | 2 | my ($self, $item, $loop) = @_; | 
| 289 |  |  |  |  |  |  |  | 
| 290 | 1 | 50 |  |  |  | 4 | die "Can't use \@loop outside of for\n"  unless $loop; | 
| 291 | 1 |  |  |  |  | 3 | return $loop; | 
| 292 |  |  |  |  |  |  | } | 
| 293 |  |  |  |  |  |  |  | 
| 294 |  |  |  |  |  |  | #---------------------------------------------------------------------- | 
| 295 |  |  |  |  |  |  | # Return the name of the current item in a loop | 
| 296 |  |  |  |  |  |  |  | 
| 297 |  |  |  |  |  |  | sub get_name { | 
| 298 | 149 |  |  | 149 | 0 | 286 | my ($self, $item) = @_; | 
| 299 | 149 |  |  |  |  | 285 | return $item; | 
| 300 |  |  |  |  |  |  | } | 
| 301 |  |  |  |  |  |  |  | 
| 302 |  |  |  |  |  |  | #---------------------------------------------------------------------- | 
| 303 |  |  |  |  |  |  | # Get the current target | 
| 304 |  |  |  |  |  |  |  | 
| 305 |  |  |  |  |  |  | sub get_target { | 
| 306 | 12 |  |  | 12 | 0 | 2379 | my ($self, $item, $loop) = @_; | 
| 307 | 12 |  |  |  |  | 38 | return $self->find_target(0, $item, $loop); | 
| 308 |  |  |  |  |  |  | } | 
| 309 |  |  |  |  |  |  |  | 
| 310 |  |  |  |  |  |  | #---------------------------------------------------------------------- | 
| 311 |  |  |  |  |  |  | # Get the next target | 
| 312 |  |  |  |  |  |  |  | 
| 313 |  |  |  |  |  |  | sub get_target_next { | 
| 314 | 9 |  |  | 9 | 0 | 2071 | my ($self, $item, $loop) = @_; | 
| 315 | 9 |  |  |  |  | 26 | return $self->find_target(1, $item, $loop); | 
| 316 |  |  |  |  |  |  | } | 
| 317 |  |  |  |  |  |  |  | 
| 318 |  |  |  |  |  |  | #---------------------------------------------------------------------- | 
| 319 |  |  |  |  |  |  | # Get the previous target | 
| 320 |  |  |  |  |  |  |  | 
| 321 |  |  |  |  |  |  | sub get_target_previous { | 
| 322 | 9 |  |  | 9 | 0 | 1929 | my ($self, $item, $loop) = @_; | 
| 323 | 9 |  |  |  |  | 27 | return $self->find_target(-1, $item, $loop); | 
| 324 |  |  |  |  |  |  | } | 
| 325 |  |  |  |  |  |  |  | 
| 326 |  |  |  |  |  |  |  | 
| 327 |  |  |  |  |  |  | #---------------------------------------------------------------------- | 
| 328 |  |  |  |  |  |  | # Augment the array to be sorted with the column to sort it by | 
| 329 |  |  |  |  |  |  | sub make_augmented { | 
| 330 | 153 |  |  | 153 | 0 | 348 | my ($self, $sort_column, $data_column) = @_; | 
| 331 |  |  |  |  |  |  |  | 
| 332 | 153 |  |  |  |  | 271 | my @augmented_list; | 
| 333 | 153 |  |  |  |  | 479 | for (my $i = 0; $i < @$sort_column; $i++) { | 
| 334 | 220 |  |  |  |  | 697 | push(@augmented_list, [$sort_column->[$i], $data_column->[$i]]); | 
| 335 |  |  |  |  |  |  | } | 
| 336 |  |  |  |  |  |  |  | 
| 337 | 153 |  |  |  |  | 490 | return @augmented_list; | 
| 338 |  |  |  |  |  |  | } | 
| 339 |  |  |  |  |  |  |  | 
| 340 |  |  |  |  |  |  | #---------------------------------------------------------------------- | 
| 341 |  |  |  |  |  |  | # Merge two sorted lists of augmented filenames | 
| 342 |  |  |  |  |  |  |  | 
| 343 |  |  |  |  |  |  | sub merge_augmented { | 
| 344 | 19 |  |  | 19 | 0 | 42 | my ($self, $list1, $list2) = @_; | 
| 345 |  |  |  |  |  |  |  | 
| 346 | 19 |  |  |  |  | 37 | my @merged_list = (); | 
| 347 | 19 |  |  |  |  | 37 | my $sort_reverse = 1; | 
| 348 | 19 |  |  |  |  | 37 | my $comparer = $self->file_comparer($sort_reverse); | 
| 349 |  |  |  |  |  |  |  | 
| 350 | 19 |  | 66 |  |  | 130 | while(@$list1 && @$list2) { | 
| 351 | 3 | 100 |  |  |  | 11 | last if @merged_list == $self->{list_length}; | 
| 352 | 2 | 50 |  |  |  | 5 | if ($comparer->($list1->[0], $list2->[0]) > 0) { | 
| 353 | 2 |  |  |  |  | 8 | push(@merged_list, shift @$list2); | 
| 354 |  |  |  |  |  |  | } else { | 
| 355 | 0 |  |  |  |  | 0 | push(@merged_list, shift @$list1); | 
| 356 |  |  |  |  |  |  | } | 
| 357 |  |  |  |  |  |  | } | 
| 358 |  |  |  |  |  |  |  | 
| 359 | 19 |  |  |  |  | 50 | while (@$list1) { | 
| 360 | 1 | 50 |  |  |  | 23 | last if @merged_list == $self->{list_length}; | 
| 361 | 0 |  |  |  |  | 0 | push(@merged_list, shift @$list1); | 
| 362 |  |  |  |  |  |  | } | 
| 363 |  |  |  |  |  |  |  | 
| 364 | 19 |  |  |  |  | 43 | while (@$list2) { | 
| 365 | 20 | 100 |  |  |  | 45 | last if @merged_list == $self->{list_length}; | 
| 366 | 17 |  |  |  |  | 43 | push(@merged_list, shift @$list2); | 
| 367 |  |  |  |  |  |  | } | 
| 368 |  |  |  |  |  |  |  | 
| 369 | 19 |  |  |  |  | 91 | return \@merged_list; | 
| 370 |  |  |  |  |  |  | } | 
| 371 |  |  |  |  |  |  |  | 
| 372 |  |  |  |  |  |  | #---------------------------------------------------------------------- | 
| 373 |  |  |  |  |  |  | # Get a reference value and check it for agreement with the sigil | 
| 374 |  |  |  |  |  |  |  | 
| 375 |  |  |  |  |  |  | sub ref_value { | 
| 376 | 513 |  |  | 513 | 0 | 3706 | my ($self, $value, $sigil, $data_field) = @_; | 
| 377 |  |  |  |  |  |  |  | 
| 378 | 513 |  |  |  |  | 772 | my ($check, $ref_value); | 
| 379 | 513 | 100 |  |  |  | 1063 | $value = '' unless defined $value; | 
| 380 |  |  |  |  |  |  |  | 
| 381 | 513 | 100 |  |  |  | 1338 | if ($sigil eq '$'){ | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 382 | 276 | 100 |  |  |  | 509 | if (ref $value ne 'SCALAR') { | 
| 383 |  |  |  |  |  |  | # Convert data structures for inclusion in template | 
| 384 | 275 |  |  |  |  | 774 | $value = fio_flatten($value); | 
| 385 | 275 |  |  |  |  | 474 | $ref_value = \$value; | 
| 386 |  |  |  |  |  |  | } else { | 
| 387 | 1 |  |  |  |  | 3 | $ref_value = $value; | 
| 388 |  |  |  |  |  |  | } | 
| 389 | 276 |  |  |  |  | 560 | $check = ref $ref_value eq 'SCALAR'; | 
| 390 |  |  |  |  |  |  |  | 
| 391 |  |  |  |  |  |  | } elsif ($sigil eq '@') { | 
| 392 | 47 |  |  |  |  | 85 | $ref_value = $value; | 
| 393 | 47 |  |  |  |  | 118 | $check = ref $ref_value eq 'ARRAY'; | 
| 394 |  |  |  |  |  |  |  | 
| 395 |  |  |  |  |  |  | } elsif ($sigil eq '') { | 
| 396 | 190 | 100 |  |  |  | 398 | $ref_value = ref $value ? $value : \$value; | 
| 397 | 190 |  |  |  |  | 319 | $check = 1; | 
| 398 |  |  |  |  |  |  | } | 
| 399 |  |  |  |  |  |  |  | 
| 400 | 513 | 50 |  |  |  | 1138 | die "Unknown variable: $sigil$data_field\n" unless $check; | 
| 401 | 513 |  |  |  |  | 919 | return $ref_value; | 
| 402 |  |  |  |  |  |  | } | 
| 403 |  |  |  |  |  |  |  | 
| 404 |  |  |  |  |  |  | #---------------------------------------------------------------------- | 
| 405 |  |  |  |  |  |  | # Set up the cache for data | 
| 406 |  |  |  |  |  |  |  | 
| 407 |  |  |  |  |  |  | sub setup { | 
| 408 | 92 |  |  | 92 | 1 | 197 | my ($self) = @_; | 
| 409 |  |  |  |  |  |  |  | 
| 410 | 92 |  |  |  |  | 254 | $self->{cache} = {}; | 
| 411 |  |  |  |  |  |  | } | 
| 412 |  |  |  |  |  |  |  | 
| 413 |  |  |  |  |  |  | #---------------------------------------------------------------------- | 
| 414 |  |  |  |  |  |  | # Sort the data if it is in an array | 
| 415 |  |  |  |  |  |  |  | 
| 416 |  |  |  |  |  |  | sub sort { | 
| 417 | 424 |  |  | 424 | 0 | 1427 | my ($self, $data, $sort_field, $sort_reverse) = @_; | 
| 418 |  |  |  |  |  |  |  | 
| 419 | 424 |  |  |  |  | 591 | my $sorted_data; | 
| 420 | 424 |  |  |  |  | 1007 | my $data_field = $self->find_data_field($data); | 
| 421 |  |  |  |  |  |  |  | 
| 422 | 424 | 100 |  |  |  | 905 | if ($data_field) { | 
| 423 | 134 |  |  |  |  | 394 | my @augmented_data = $self->sort_with_field($data->{$data_field}, | 
| 424 |  |  |  |  |  |  | $sort_field, | 
| 425 |  |  |  |  |  |  | $sort_reverse); | 
| 426 |  |  |  |  |  |  |  | 
| 427 | 134 |  |  |  |  | 372 | my @stripped_data = $self->strip_augmented(@augmented_data); | 
| 428 | 134 |  |  |  |  | 453 | $sorted_data = {$data_field => \@stripped_data}; | 
| 429 |  |  |  |  |  |  |  | 
| 430 |  |  |  |  |  |  | } else { | 
| 431 | 290 |  |  |  |  | 437 | $sorted_data = $data; | 
| 432 |  |  |  |  |  |  | } | 
| 433 |  |  |  |  |  |  |  | 
| 434 | 424 |  |  |  |  | 814 | return $sorted_data; | 
| 435 |  |  |  |  |  |  | } | 
| 436 |  |  |  |  |  |  |  | 
| 437 |  |  |  |  |  |  | #---------------------------------------------------------------------- | 
| 438 |  |  |  |  |  |  | # Sort augmented list by swartzian transform | 
| 439 |  |  |  |  |  |  |  | 
| 440 |  |  |  |  |  |  | sub sort_augmented { | 
| 441 | 153 |  |  | 153 | 0 | 355 | my ($self, $sort_reverse, @augmented_data) = @_; | 
| 442 |  |  |  |  |  |  |  | 
| 443 | 153 |  |  |  |  | 417 | my $comparer = $self->file_comparer($sort_reverse); | 
| 444 | 153 |  |  |  |  | 401 | @augmented_data = sort $comparer @augmented_data; | 
| 445 | 153 |  |  |  |  | 741 | return @augmented_data; | 
| 446 |  |  |  |  |  |  | } | 
| 447 |  |  |  |  |  |  |  | 
| 448 |  |  |  |  |  |  | #---------------------------------------------------------------------- | 
| 449 |  |  |  |  |  |  | # Sort data retaining the field you sort with | 
| 450 |  |  |  |  |  |  |  | 
| 451 |  |  |  |  |  |  | sub sort_with_field { | 
| 452 | 153 |  |  | 153 | 0 | 372 | my ($self, $data_column, $sort_field, $sort_reverse) = @_; | 
| 453 | 153 | 100 |  |  |  | 374 | $sort_field = 'name' unless defined $sort_field; | 
| 454 | 153 | 100 |  |  |  | 390 | $sort_reverse = 0 unless defined $sort_reverse; | 
| 455 |  |  |  |  |  |  |  | 
| 456 | 153 |  |  |  |  | 477 | my $sort_column = $self->find_sort_column($data_column, $sort_field); | 
| 457 |  |  |  |  |  |  |  | 
| 458 | 153 |  |  |  |  | 539 | return $self->sort_augmented($sort_reverse, | 
| 459 |  |  |  |  |  |  | $self->make_augmented($sort_column, $data_column)); | 
| 460 |  |  |  |  |  |  | } | 
| 461 |  |  |  |  |  |  |  | 
| 462 |  |  |  |  |  |  | #---------------------------------------------------------------------- | 
| 463 |  |  |  |  |  |  | # Return the filenames from an augmented set of files | 
| 464 |  |  |  |  |  |  |  | 
| 465 |  |  |  |  |  |  | sub strip_augmented { | 
| 466 | 144 |  |  | 144 | 0 | 276 | my $self = shift @_; | 
| 467 | 144 |  |  |  |  | 325 | return map {$_->[1]} @_; | 
|  | 211 |  |  |  |  | 542 |  | 
| 468 |  |  |  |  |  |  | } | 
| 469 |  |  |  |  |  |  |  | 
| 470 |  |  |  |  |  |  | #---------------------------------------------------------------------- | 
| 471 |  |  |  |  |  |  | # Split the sigil off from the variable name from a template | 
| 472 |  |  |  |  |  |  |  | 
| 473 |  |  |  |  |  |  | sub split_name { | 
| 474 | 513 |  |  | 513 | 0 | 4652 | my ($self, $variable_name) = @_; | 
| 475 |  |  |  |  |  |  |  | 
| 476 | 513 |  |  |  |  | 858 | my $name = $variable_name; | 
| 477 | 513 |  |  |  |  | 1637 | $name =~ s/^([\$\@])//; | 
| 478 | 513 |  | 100 |  |  | 2885 | my $sigil = $1 || ''; | 
| 479 |  |  |  |  |  |  |  | 
| 480 | 513 |  |  |  |  | 1452 | return ($sigil, $name); | 
| 481 |  |  |  |  |  |  | } | 
| 482 |  |  |  |  |  |  |  | 
| 483 |  |  |  |  |  |  | 1; | 
| 484 |  |  |  |  |  |  |  | 
| 485 |  |  |  |  |  |  | =pod | 
| 486 |  |  |  |  |  |  |  | 
| 487 |  |  |  |  |  |  | =encoding utf-8 | 
| 488 |  |  |  |  |  |  |  | 
| 489 |  |  |  |  |  |  | =head1 NAME | 
| 490 |  |  |  |  |  |  |  | 
| 491 |  |  |  |  |  |  | App::Followme::BaseData | 
| 492 |  |  |  |  |  |  |  | 
| 493 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 494 |  |  |  |  |  |  |  | 
| 495 |  |  |  |  |  |  | use App::Followme::BaseData; | 
| 496 |  |  |  |  |  |  | my $meta = App::Followme::BaseData->new(); | 
| 497 |  |  |  |  |  |  | my %data = $meta->build($name, $filename); | 
| 498 |  |  |  |  |  |  |  | 
| 499 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 500 |  |  |  |  |  |  |  | 
| 501 |  |  |  |  |  |  | This module is the base class for all metadata classes and provides the build | 
| 502 |  |  |  |  |  |  | method used to interface metadata classes with the App::Followme::Template | 
| 503 |  |  |  |  |  |  | class. | 
| 504 |  |  |  |  |  |  |  | 
| 505 |  |  |  |  |  |  | Followme uses templates to construct web pages. These templates contain | 
| 506 |  |  |  |  |  |  | variables whose values are computed by calling the build method of the metadata | 
| 507 |  |  |  |  |  |  | object, which is passed as an argument to the template function. The build | 
| 508 |  |  |  |  |  |  | method returns either a reference to a scalar or list. The names correspond to | 
| 509 |  |  |  |  |  |  | the variable names in the template. This class contains the build method, which | 
| 510 |  |  |  |  |  |  | couples the variable name to the metadata object method that computes the value | 
| 511 |  |  |  |  |  |  | of the variable. | 
| 512 |  |  |  |  |  |  |  | 
| 513 |  |  |  |  |  |  | =head1 METHODS | 
| 514 |  |  |  |  |  |  |  | 
| 515 |  |  |  |  |  |  | There is only one public method, build. | 
| 516 |  |  |  |  |  |  |  | 
| 517 |  |  |  |  |  |  | =over 4 | 
| 518 |  |  |  |  |  |  |  | 
| 519 |  |  |  |  |  |  | =item my %data = $meta->build($name, $filename); | 
| 520 |  |  |  |  |  |  |  | 
| 521 |  |  |  |  |  |  | Build a variable's value. The first argument is the name of the variable | 
| 522 |  |  |  |  |  |  | to be built. The second argument is the filename the variable is computed for. | 
| 523 |  |  |  |  |  |  | If the variable returned is a list of files, this variable should be left | 
| 524 |  |  |  |  |  |  | undefined. | 
| 525 |  |  |  |  |  |  |  | 
| 526 |  |  |  |  |  |  | =back | 
| 527 |  |  |  |  |  |  |  | 
| 528 |  |  |  |  |  |  | =head1 VARIABLES | 
| 529 |  |  |  |  |  |  |  | 
| 530 |  |  |  |  |  |  | The base metadata class can evaluate the following variables. When passing | 
| 531 |  |  |  |  |  |  | a name to the build method, the sigil should not be used. All these variables | 
| 532 |  |  |  |  |  |  | can only be used inside a for block. | 
| 533 |  |  |  |  |  |  |  | 
| 534 |  |  |  |  |  |  | =over 4 | 
| 535 |  |  |  |  |  |  |  | 
| 536 |  |  |  |  |  |  | =item @loop | 
| 537 |  |  |  |  |  |  |  | 
| 538 |  |  |  |  |  |  | A list with all the loop items from the immediately enclosing for block. | 
| 539 |  |  |  |  |  |  |  | 
| 540 |  |  |  |  |  |  | =item $count | 
| 541 |  |  |  |  |  |  |  | 
| 542 |  |  |  |  |  |  | The count of the current item in the for block.The count starts at one. | 
| 543 |  |  |  |  |  |  |  | 
| 544 |  |  |  |  |  |  | =item $is_first | 
| 545 |  |  |  |  |  |  |  | 
| 546 |  |  |  |  |  |  | One if this is the first item in the for block, zero otherwise. | 
| 547 |  |  |  |  |  |  |  | 
| 548 |  |  |  |  |  |  | =item $is_last | 
| 549 |  |  |  |  |  |  |  | 
| 550 |  |  |  |  |  |  | One if this is the last item in the for block, zero otherwise | 
| 551 |  |  |  |  |  |  |  | 
| 552 |  |  |  |  |  |  | =item $name | 
| 553 |  |  |  |  |  |  |  | 
| 554 |  |  |  |  |  |  | The name of the current item in the for block. | 
| 555 |  |  |  |  |  |  |  | 
| 556 |  |  |  |  |  |  | =item $target | 
| 557 |  |  |  |  |  |  |  | 
| 558 |  |  |  |  |  |  | A string that can be used as a target for the location of the current item | 
| 559 |  |  |  |  |  |  | in the page. | 
| 560 |  |  |  |  |  |  |  | 
| 561 |  |  |  |  |  |  | =item $target_next | 
| 562 |  |  |  |  |  |  |  | 
| 563 |  |  |  |  |  |  | A string that can be used as a target for the location of the next item | 
| 564 |  |  |  |  |  |  | in the page. Empty if there is no next item. | 
| 565 |  |  |  |  |  |  |  | 
| 566 |  |  |  |  |  |  | =item $target_previous | 
| 567 |  |  |  |  |  |  |  | 
| 568 |  |  |  |  |  |  | A string that can be used as a target for the location of the previous item | 
| 569 |  |  |  |  |  |  | in the page. Empty if there is no previous item. | 
| 570 |  |  |  |  |  |  |  | 
| 571 |  |  |  |  |  |  | =back | 
| 572 |  |  |  |  |  |  |  | 
| 573 |  |  |  |  |  |  | =head1 CONFIGURATION | 
| 574 |  |  |  |  |  |  |  | 
| 575 |  |  |  |  |  |  | There are two parameters: | 
| 576 |  |  |  |  |  |  |  | 
| 577 |  |  |  |  |  |  | =over 4 | 
| 578 |  |  |  |  |  |  |  | 
| 579 |  |  |  |  |  |  | =item list_length | 
| 580 |  |  |  |  |  |  |  | 
| 581 |  |  |  |  |  |  | This determines the number of filenames in a merged list. The default | 
| 582 |  |  |  |  |  |  | value of this parameter is 5 | 
| 583 |  |  |  |  |  |  |  | 
| 584 |  |  |  |  |  |  | =item target_prefix | 
| 585 |  |  |  |  |  |  |  | 
| 586 |  |  |  |  |  |  | The prefix used to build the target names. The default value is 'target'. | 
| 587 |  |  |  |  |  |  |  | 
| 588 |  |  |  |  |  |  | =back | 
| 589 |  |  |  |  |  |  |  | 
| 590 |  |  |  |  |  |  | =head1 LICENSE | 
| 591 |  |  |  |  |  |  |  | 
| 592 |  |  |  |  |  |  | Copyright (C) Bernie Simon. | 
| 593 |  |  |  |  |  |  |  | 
| 594 |  |  |  |  |  |  | This library is free software; you can redistribute it and/or modify | 
| 595 |  |  |  |  |  |  | it under the same terms as Perl itself. | 
| 596 |  |  |  |  |  |  |  | 
| 597 |  |  |  |  |  |  | =head1 AUTHOR | 
| 598 |  |  |  |  |  |  |  | 
| 599 |  |  |  |  |  |  | Bernie Simon E<lt>bernie.simon@gmail.comE<gt> | 
| 600 |  |  |  |  |  |  |  | 
| 601 |  |  |  |  |  |  | =cut |