1 package SL::MoreCommon;
4 our @ISA = qw(Exporter);
6 our @EXPORT = qw(save_form restore_form compare_numbers any cross);
7 our @EXPORT_OK = qw(ary_union ary_intersect ary_diff listify ary_to_hash);
9 use List::MoreUtils qw(zip);
17 $main::lxdebug->enter_sub();
19 my @dont_dump_keys = @_;
20 my %not_dumped_values;
22 foreach my $key (@dont_dump_keys) {
23 $not_dumped_values{$key} = $main::form->{$key};
24 delete $main::form->{$key};
27 my $old_form = YAML::Dump($main::form);
28 $old_form =~ s|!|!:|g;
29 $old_form =~ s|\n|!n|g;
30 $old_form =~ s|\r|!r|g;
32 map { $main::form->{$_} = $not_dumped_values{$_} } keys %not_dumped_values;
34 $main::lxdebug->leave_sub();
40 $main::lxdebug->enter_sub();
42 my ($old_form, $no_delete, @keep_vars) = @_;
44 my $form = $main::form;
45 my %keep_vars_map = map { $_ => 1 } @keep_vars;
47 map { delete $form->{$_} if (!$keep_vars_map{$_}); } keys %{$form} unless ($no_delete);
49 $old_form =~ s|!r|\r|g;
50 $old_form =~ s|!n|\n|g;
51 $old_form =~ s|![!:]|!|g;
53 my $new_form = YAML::Load($old_form);
54 map { $form->{$_} = $new_form->{$_} if (!$keep_vars_map{$_}) } keys %{ $new_form };
56 $main::lxdebug->leave_sub();
60 $main::lxdebug->enter_sub();
62 my ($a, $a_unit, $b, $b_unit) = @_;
64 $main::all_units ||= AM->retrieve_units(\%main::myconfig, $main::form);
65 my $units = $main::all_units;
67 if (!$units->{$a_unit} || !$units->{$b_unit} || ($units->{$a_unit}->{base_unit} ne $units->{$b_unit}->{base_unit})) {
68 $main::lxdebug->leave_sub();
72 $a *= $units->{$a_unit}->{factor};
73 $b *= $units->{$b_unit}->{factor};
75 $main::lxdebug->leave_sub();
92 local (*A, *B) = @_; # syms for caller's input arrays
95 my ($caller_a, $caller_b) = do {
98 \*{$pkg.'::a'}, \*{$pkg.'::b'};
101 local(*$caller_a, *$caller_b);
103 # This map expression is also the return value.
104 map { my $a_index = $_;
105 map { my $b_index = $_;
106 # assign to $a, $b as refs to caller's array elements
107 (*$caller_a, *$caller_b) = \($A[$a_index], $B[$b_index]);
108 $op->(); # perform the transformation
113 sub _ary_calc_union_intersect {
118 foreach my $e (@$a, @$b) { $count{$e}++ }
122 foreach my $e (keys %count) {
124 push @isect, $e if $count{$e} == 2;
127 return (\@union, \@isect);
131 return @{ (_ary_calc_union_intersect @_)[0] };
135 return @{ (_ary_calc_union_intersect @_)[1] };
140 my %in_b = map { $_ => 1 } @$b;
141 return grep { !$in_b{$_} } @$a;
145 my @ary = scalar @_ > 1 ? @_ : ref $_[0] eq 'ARRAY' ? @{ $_[0] } : (@_);
146 return wantarray ? @ary : scalar @ary;
151 my $value_key = shift;
153 return map { ($_, 1) } @_ if !defined($idx_key);
155 my @indexes = map { ref $_ eq 'HASH' ? $_->{ $idx_key } : $_->$idx_key(); } @_;
157 !defined($value_key) ? $_
158 : ref $_ eq 'HASH' ? $_->{ $value_key }
162 return zip(@indexes, @values);
171 SL::MoreCommon.pm - helper functions
175 this is a collection of helper functions used in Lx-Office.
176 Most of them are either obvious or too obscure to care about unless you really have to.
177 The exceptions are documented here.
186 A lot of the old sql-ledger routines are strictly procedural. They search for params in the $form object, do stuff with it, and return a status code.
188 Once in a while you'll want something from such a function without altering $form. Yeah, you could rewrite the routine from scratch... not. Just save you form, execute the routine, grab your results, and restore the previous form while you curse at the original design.
190 =item cross BLOCK ARRAY ARRAY
192 Evaluates BLOCK for each combination of elements in ARRAY1 and ARRAY2
193 and returns a new list consisting of BLOCK's return values.
194 The two elements are set to $a and $b.
195 Note that those two are aliases to the original value so changing them
196 will modify the input arrays.
198 # append each to each
201 @x = cross { "$a$b" } @a, @b;
202 # returns a1, a2, a3, b1, b2, b3, c1, c2, c3
204 As cross expects an array but returns a list it is not directly chainable
205 at the moment. This will be corrected in the future.
207 =item ary_to_hash INDEX_KEY, VALUE_KEY, ARRAY
209 Returns a hash with the content of ARRAY based on the values of
210 INDEX_KEY and VALUE_KEY.
212 If INDEX_KEY is undefined then the elements of ARRAY are the keys and
213 '1' is the value for each of them.
215 If INDEX_KEY is defined then each element of ARRAY is checked whether
216 or not it is a hash. If it is then its element at the position
217 INDEX_KEY will be the resulting hash element's key. Otherwise the
218 element is assumed to be a blessed reference, and its INDEX_KEY
219 function will be called.
221 The values of the resulting hash follow a similar pattern. If
222 VALUE_KEY is undefined then the current element itself is the new hash
223 element's value. If the current element is a hash then its element at
224 the position VALUE_KEY will be the resulting hash element's
225 key. Otherwise the element is assumed to be a blessed reference, and
226 its VALUE_KEY function will be called.